VirtualBox

Changeset 22554 in vbox


Ignore:
Timestamp:
Aug 28, 2009 2:31:02 PM (15 years ago)
Author:
vboxsync
Message:

SSM: Adding states for the live stages. Moving code around so the write and read parts are grouped together instead of being intermixed.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/SSM.cpp

    r22480 r22554  
    242242
    243243/** Start structure magic. (Isacc Asimov) */
    244 #define SSMR3STRUCT_BEGIN                       0x19200102
     244#define SSMR3STRUCT_BEGIN                       UINT32_C(0x19200102)
    245245/** End structure magic. (Isacc Asimov) */
    246 #define SSMR3STRUCT_END                         0x19920406
     246#define SSMR3STRUCT_END                         UINT32_C(0x19920406)
    247247
    248248
     
    269269
    270270
     271/**
     272 * Asserts that the handle is writable and returns with VERR_SSM_INVALID_STATE
     273 * if it isn't.
     274 */
     275#define SSM_ASSERT_WRITEABLE_RET(pSSM) \
     276    AssertMsgReturn(   pSSM->enmOp == SSMSTATE_SAVE_EXEC \
     277                    || pSSM->enmOp == SSMSTATE_LIVE_EXEC,\
     278                    ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     279
     280/**
     281 * Asserts that the handle is readable and returns with VERR_SSM_INVALID_STATE
     282 * if it isn't.
     283 */
     284#define SSM_ASSERT_READABLE_RET(pSSM) \
     285    AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC \
     286                    || pSSM->enmOp == SSMSTATE_OPEN_READ,\
     287                    ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     288
     289
    271290/*******************************************************************************
    272291*   Structures and Typedefs                                                    *
     
    276295{
    277296    SSMSTATE_INVALID = 0,
     297    SSMSTATE_LIVE_PREP,
     298    SSMSTATE_LIVE_EXEC,
     299    SSMSTATE_LIVE_VOTE,
    278300    SSMSTATE_SAVE_PREP,
    279301    SSMSTATE_SAVE_EXEC,
     
    755777static DECLCALLBACK(int)    ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPhase);
    756778static int                  ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit);
     779
    757780static int                  ssmR3StrmWriteBuffers(PSSMSTRM pStrm);
    758781static int                  ssmR3StrmReadMore(PSSMSTRM pStrm);
    759 static int                  ssmR3CalcChecksum(RTFILE File, uint64_t cbFile, uint32_t *pu32CRC);
    760 static void                 ssmR3Progress(PSSMHANDLE pSSM, uint64_t cbAdvance);
    761 static PSSMUNIT             ssmR3Find(PVM pVM, const char *pszName, uint32_t uInstance);
    762 static int                  ssmR3DataWriteFinish(PSSMHANDLE pSSM);
    763 static void                 ssmR3DataWriteBegin(PSSMHANDLE pSSM);
    764 static int                  ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
     782
    765783static int                  ssmR3DataFlushBuffer(PSSMHANDLE pSSM);
    766 static int                  ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf);
    767 static void                 ssmR3DataReadFinishV1(PSSMHANDLE pSSM);
    768 static void                 ssmR3DataReadBeginV2(PSSMHANDLE pSSM);
    769 static void                 ssmR3DataReadFinishV2(PSSMHANDLE pSSM);
    770784static int                  ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM);
    771 static int                  ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf);
     785
    772786
    773787
     
    22612275        PSSMSTRMBUF pBuf = pStrm->pCur; Assert(pBuf);
    22622276        pStrm->u32StreamCRC = RTCrc32Process(pStrm->u32StreamCRC, &pBuf->abData[pStrm->offStreamCRC], pStrm->off - pStrm->offStreamCRC);
    2263 //if (pStrm->offStreamCRC == 0 && pStrm->off == 0x40)
    2264 //    LogAlways(("ssmR3StrmCurCRC: %08x\n%.64Rhxd\n", pStrm->u32StreamCRC, pBuf->abData));
    22652277        pStrm->offStreamCRC = pStrm->off;
    22662278    }
     
    25442556                             / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare);
    25452557    }
     2558}
     2559
     2560
     2561/**
     2562 * Finishes a data unit.
     2563 * All buffers and compressor instances are flushed and destroyed.
     2564 *
     2565 * @returns VBox status.
     2566 * @param   pSSM            SSM operation handle.
     2567 */
     2568static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
     2569{
     2570    //Log2(("ssmR3DataWriteFinish: %#010llx start\n", ssmR3StrmTell(&pSSM->Strm)));
     2571    int rc = ssmR3DataFlushBuffer(pSSM);
     2572    if (RT_SUCCESS(rc))
     2573        return VINF_SUCCESS;
     2574
     2575    if (RT_SUCCESS(pSSM->rc))
     2576        pSSM->rc = rc;
     2577    Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
     2578    return rc;
     2579}
     2580
     2581
     2582/**
     2583 * Begins writing the data of a data unit.
     2584 *
     2585 * Errors are signalled via pSSM->rc.
     2586 *
     2587 * @param   pSSM            The saved state handle.
     2588 */
     2589static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
     2590{
     2591    pSSM->offUnit = 0;
     2592}
     2593
     2594
     2595/**
     2596 * Writes a record to the current data item in the saved state file.
     2597 *
     2598 * @returns VBox status code. Sets pSSM->rc on failure.
     2599 * @param   pSSM            The saved state handle.
     2600 * @param   pvBuf           The bits to write.
     2601 * @param   cbBuf           The number of bytes to write.
     2602 */
     2603static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
     2604{
     2605    Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
     2606          ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
     2607
     2608    /*
     2609     * Check that everything is fine.
     2610     */
     2611    if (RT_FAILURE(pSSM->rc))
     2612        return pSSM->rc;
     2613
     2614    /*
     2615     * Write the data item in 1MB chunks for progress indicator reasons.
     2616     */
     2617    while (cbBuf > 0)
     2618    {
     2619        size_t cbChunk = RT_MIN(cbBuf, _1M);
     2620        int rc = ssmR3StrmWrite(&pSSM->Strm, pvBuf, cbChunk);
     2621        if (RT_FAILURE(rc))
     2622            return rc;
     2623        pSSM->offUnit += cbChunk;
     2624        cbBuf -= cbChunk;
     2625        pvBuf = (char *)pvBuf + cbChunk;
     2626    }
     2627
     2628    return VINF_SUCCESS;
     2629}
     2630
     2631
     2632/**
     2633 * Writes a record header for the specified amount of data.
     2634 *
     2635 * @returns VBox status code. Sets pSSM->rc on failure.
     2636 * @param   pSSM            The saved state handle
     2637 * @param   cb              The amount of data.
     2638 * @param   u8TypeAndFlags  The record type and flags.
     2639 */
     2640static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
     2641{
     2642    size_t  cbHdr;
     2643    uint8_t abHdr[8];
     2644    abHdr[0] = u8TypeAndFlags;
     2645    if (cb < 0x80)
     2646    {
     2647        cbHdr = 2;
     2648        abHdr[1] = (uint8_t)cb;
     2649    }
     2650    else if (cb < 0x00000800)
     2651    {
     2652        cbHdr = 3;
     2653        abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
     2654        abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
     2655    }
     2656    else if (cb < 0x00010000)
     2657    {
     2658        cbHdr = 4;
     2659        abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
     2660        abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
     2661        abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
     2662    }
     2663    else if (cb < 0x00200000)
     2664    {
     2665        cbHdr = 5;
     2666        abHdr[1] = (uint8_t)(0xf0 |  (cb >> 18));
     2667        abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
     2668        abHdr[3] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
     2669        abHdr[4] = (uint8_t)(0x80 |  (cb        & 0x3f));
     2670    }
     2671    else if (cb < 0x04000000)
     2672    {
     2673        cbHdr = 6;
     2674        abHdr[1] = (uint8_t)(0xf8 |  (cb >> 24));
     2675        abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
     2676        abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
     2677        abHdr[4] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
     2678        abHdr[5] = (uint8_t)(0x80 |  (cb        & 0x3f));
     2679    }
     2680    else if (cb <= 0x7fffffff)
     2681    {
     2682        cbHdr = 7;
     2683        abHdr[1] = (uint8_t)(0xfc |  (cb >> 30));
     2684        abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
     2685        abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
     2686        abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
     2687        abHdr[5] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
     2688        abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
     2689    }
     2690    else
     2691        AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_INTERNAL_ERROR);
     2692
     2693    Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
     2694          ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
     2695
     2696    return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
     2697}
     2698
     2699
     2700/**
     2701 * Worker that flushes the buffered data.
     2702 *
     2703 * @returns VBox status code. Will set pSSM->rc on error.
     2704 * @param   pSSM            The saved state handle.
     2705 */
     2706static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
     2707{
     2708    /*
     2709     * Check how much there current is in the buffer.
     2710     */
     2711    uint32_t cb = pSSM->u.Write.offDataBuffer;
     2712    if (!cb)
     2713        return pSSM->rc;
     2714    pSSM->u.Write.offDataBuffer = 0;
     2715
     2716    /*
     2717     * Write a record header and then the data.
     2718     * (No need for fancy optimizations here any longer since the stream is
     2719     * fully buffered.)
     2720     */
     2721    int rc = ssmR3DataWriteRecHdr(pSSM, cb, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
     2722    if (RT_SUCCESS(rc))
     2723        rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
     2724    ssmR3Progress(pSSM, cb);
     2725    return rc;
     2726}
     2727
     2728
     2729/**
     2730 * ssmR3DataWrite worker that writes big stuff.
     2731 *
     2732 * @returns VBox status code
     2733 * @param   pSSM            The saved state handle.
     2734 * @param   pvBuf           The bits to write.
     2735 * @param   cbBuf           The number of bytes to write.
     2736 */
     2737static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
     2738{
     2739    int rc = ssmR3DataFlushBuffer(pSSM);
     2740    if (RT_SUCCESS(rc))
     2741    {
     2742        /*
     2743         * Split it up into compression blocks.
     2744         */
     2745        for (;;)
     2746        {
     2747            AssertCompile(SSM_ZIP_BLOCK_SIZE == PAGE_SIZE);
     2748            if (    cbBuf >= SSM_ZIP_BLOCK_SIZE
     2749                && (    ((uintptr_t)pvBuf & 0xf)
     2750                    ||  !ASMMemIsZeroPage(pvBuf))
     2751               )
     2752            {
     2753                /*
     2754                 * Compress it.
     2755                 */
     2756                AssertCompile(1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE < 0x00010000);
     2757                uint8_t *pb;
     2758                rc = ssmR3StrmReserveWriteBufferSpace(&pSSM->Strm, 1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE, &pb);
     2759                if (RT_FAILURE(rc))
     2760                    break;
     2761                size_t cbRec = SSM_ZIP_BLOCK_SIZE - (SSM_ZIP_BLOCK_SIZE / 16);
     2762                rc = RTZipBlockCompress(RTZIPTYPE_LZF, RTZIPLEVEL_FAST, 0 /*fFlags*/,
     2763                                        pvBuf, SSM_ZIP_BLOCK_SIZE,
     2764                                        pb + 1 + 3 + 1, cbRec, &cbRec);
     2765                if (RT_SUCCESS(rc))
     2766                {
     2767                    pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF;
     2768                    pb[4] = SSM_ZIP_BLOCK_SIZE / _1K;
     2769                    cbRec += 1;
     2770                }
     2771                else
     2772                {
     2773                    pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
     2774                    memcpy(&pb[4], pvBuf, SSM_ZIP_BLOCK_SIZE);
     2775                    cbRec = SSM_ZIP_BLOCK_SIZE;
     2776                }
     2777                pb[1] = (uint8_t)(0xe0 | ( cbRec >> 12));
     2778                pb[2] = (uint8_t)(0x80 | ((cbRec >>  6) & 0x3f));
     2779                pb[3] = (uint8_t)(0x80 | ( cbRec        & 0x3f));
     2780                cbRec += 1 + 3;
     2781                rc = ssmR3StrmCommitWriteBufferSpace(&pSSM->Strm, cbRec);
     2782                if (RT_FAILURE(rc))
     2783                    break;
     2784
     2785                pSSM->offUnit += cbRec;
     2786                ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
     2787
     2788                /* advance */
     2789                if (cbBuf == SSM_ZIP_BLOCK_SIZE)
     2790                    return VINF_SUCCESS;
     2791                cbBuf -= SSM_ZIP_BLOCK_SIZE;
     2792                pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
     2793            }
     2794            else if (cbBuf >= SSM_ZIP_BLOCK_SIZE)
     2795            {
     2796                /*
     2797                 * Zero block.
     2798                 */
     2799                uint8_t abRec[3];
     2800                abRec[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_ZERO;
     2801                abRec[1] = 1;
     2802                abRec[2] = SSM_ZIP_BLOCK_SIZE / _1K;
     2803                Log3(("ssmR3DataWriteBig: %08llx|%08llx/%08x: ZERO\n", ssmR3StrmTell(&pSSM->Strm) + 2, pSSM->offUnit + 2, 1));
     2804                rc = ssmR3DataWriteRaw(pSSM, &abRec[0], sizeof(abRec));
     2805                if (RT_FAILURE(rc))
     2806                    break;
     2807
     2808                /* advance */
     2809                ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
     2810                if (cbBuf == SSM_ZIP_BLOCK_SIZE)
     2811                    return VINF_SUCCESS;
     2812                cbBuf -= SSM_ZIP_BLOCK_SIZE;
     2813                pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
     2814            }
     2815            else
     2816            {
     2817                /*
     2818                 * Less than one block left, store it the simple way.
     2819                 */
     2820                rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
     2821                if (RT_SUCCESS(rc))
     2822                    rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
     2823                ssmR3Progress(pSSM, cbBuf);
     2824                break;
     2825            }
     2826        }
     2827    }
     2828    return rc;
     2829}
     2830
     2831
     2832/**
     2833 * ssmR3DataWrite worker that is called when there isn't enough room in the
     2834 * buffer for the current chunk of data.
     2835 *
     2836 * This will first flush the buffer and then add the new bits to it.
     2837 *
     2838 * @returns VBox status code
     2839 * @param   pSSM            The saved state handle.
     2840 * @param   pvBuf           The bits to write.
     2841 * @param   cbBuf           The number of bytes to write.
     2842 */
     2843static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
     2844{
     2845    int rc = ssmR3DataFlushBuffer(pSSM);
     2846    if (RT_SUCCESS(rc))
     2847    {
     2848        memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
     2849        pSSM->u.Write.offDataBuffer = (uint32_t)cbBuf;
     2850    }
     2851    return rc;
     2852}
     2853
     2854
     2855/**
     2856 * Writes data to the current data unit.
     2857 *
     2858 * This is an inlined wrapper that optimizes the small writes that so many of
     2859 * the APIs make.
     2860 *
     2861 * @returns VBox status code
     2862 * @param   pSSM            The saved state handle.
     2863 * @param   pvBuf           The bits to write.
     2864 * @param   cbBuf           The number of bytes to write.
     2865 */
     2866DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
     2867{
     2868    if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
     2869        return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
     2870    if (!cbBuf)
     2871        return VINF_SUCCESS;
     2872
     2873    uint32_t off = pSSM->u.Write.offDataBuffer;
     2874    if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
     2875        return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
     2876
     2877    memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
     2878    pSSM->u.Write.offDataBuffer = off + (uint32_t)cbBuf;
     2879    return VINF_SUCCESS;
     2880}
     2881
     2882
     2883/**
     2884 * Puts a structure.
     2885 *
     2886 * @returns VBox status code.
     2887 * @param   pSSM            The saved state handle.
     2888 * @param   pvStruct        The structure address.
     2889 * @param   paFields        The array of structure fields descriptions.
     2890 *                          The array must be terminated by a SSMFIELD_ENTRY_TERM().
     2891 */
     2892VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
     2893{
     2894    /* begin marker. */
     2895    int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
     2896    if (RT_FAILURE(rc))
     2897        return rc;
     2898
     2899    /* put the fields */
     2900    for (PCSSMFIELD pCur = paFields;
     2901         pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
     2902         pCur++)
     2903    {
     2904        rc = ssmR3DataWrite(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
     2905        if (RT_FAILURE(rc))
     2906            return rc;
     2907    }
     2908
     2909    /* end marker */
     2910    return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
     2911}
     2912
     2913
     2914/**
     2915 * Saves a boolean item to the current data unit.
     2916 *
     2917 * @returns VBox status.
     2918 * @param   pSSM            SSM operation handle.
     2919 * @param   fBool           Item to save.
     2920 */
     2921VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
     2922{
     2923    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2924    uint8_t u8 = fBool; /* enforce 1 byte size */
     2925    return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
     2926}
     2927
     2928
     2929/**
     2930 * Saves a 8-bit unsigned integer item to the current data unit.
     2931 *
     2932 * @returns VBox status.
     2933 * @param   pSSM            SSM operation handle.
     2934 * @param   u8              Item to save.
     2935 */
     2936VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
     2937{
     2938    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2939    return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
     2940}
     2941
     2942
     2943/**
     2944 * Saves a 8-bit signed integer item to the current data unit.
     2945 *
     2946 * @returns VBox status.
     2947 * @param   pSSM            SSM operation handle.
     2948 * @param   i8              Item to save.
     2949 */
     2950VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
     2951{
     2952    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2953    return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
     2954}
     2955
     2956
     2957/**
     2958 * Saves a 16-bit unsigned integer item to the current data unit.
     2959 *
     2960 * @returns VBox status.
     2961 * @param   pSSM            SSM operation handle.
     2962 * @param   u16             Item to save.
     2963 */
     2964VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
     2965{
     2966    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2967    return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
     2968}
     2969
     2970
     2971/**
     2972 * Saves a 16-bit signed integer item to the current data unit.
     2973 *
     2974 * @returns VBox status.
     2975 * @param   pSSM            SSM operation handle.
     2976 * @param   i16             Item to save.
     2977 */
     2978VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
     2979{
     2980    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2981    return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
     2982}
     2983
     2984
     2985/**
     2986 * Saves a 32-bit unsigned integer item to the current data unit.
     2987 *
     2988 * @returns VBox status.
     2989 * @param   pSSM            SSM operation handle.
     2990 * @param   u32             Item to save.
     2991 */
     2992VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
     2993{
     2994    SSM_ASSERT_WRITEABLE_RET(pSSM);
     2995    return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
     2996}
     2997
     2998
     2999/**
     3000 * Saves a 32-bit signed integer item to the current data unit.
     3001 *
     3002 * @returns VBox status.
     3003 * @param   pSSM            SSM operation handle.
     3004 * @param   i32             Item to save.
     3005 */
     3006VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
     3007{
     3008    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3009    return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
     3010}
     3011
     3012
     3013/**
     3014 * Saves a 64-bit unsigned integer item to the current data unit.
     3015 *
     3016 * @returns VBox status.
     3017 * @param   pSSM            SSM operation handle.
     3018 * @param   u64             Item to save.
     3019 */
     3020VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
     3021{
     3022    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3023    return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
     3024}
     3025
     3026
     3027/**
     3028 * Saves a 64-bit signed integer item to the current data unit.
     3029 *
     3030 * @returns VBox status.
     3031 * @param   pSSM            SSM operation handle.
     3032 * @param   i64             Item to save.
     3033 */
     3034VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
     3035{
     3036    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3037    return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
     3038}
     3039
     3040
     3041/**
     3042 * Saves a 128-bit unsigned integer item to the current data unit.
     3043 *
     3044 * @returns VBox status.
     3045 * @param   pSSM            SSM operation handle.
     3046 * @param   u128            Item to save.
     3047 */
     3048VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
     3049{
     3050    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3051    return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
     3052}
     3053
     3054
     3055/**
     3056 * Saves a 128-bit signed integer item to the current data unit.
     3057 *
     3058 * @returns VBox status.
     3059 * @param   pSSM            SSM operation handle.
     3060 * @param   i128            Item to save.
     3061 */
     3062VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
     3063{
     3064    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3065    return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
     3066}
     3067
     3068
     3069/**
     3070 * Saves a VBox unsigned integer item to the current data unit.
     3071 *
     3072 * @returns VBox status.
     3073 * @param   pSSM            SSM operation handle.
     3074 * @param   u               Item to save.
     3075 */
     3076VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
     3077{
     3078    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3079    return ssmR3DataWrite(pSSM, &u, sizeof(u));
     3080}
     3081
     3082
     3083/**
     3084 * Saves a VBox signed integer item to the current data unit.
     3085 *
     3086 * @returns VBox status.
     3087 * @param   pSSM            SSM operation handle.
     3088 * @param   i               Item to save.
     3089 */
     3090VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
     3091{
     3092    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3093    return ssmR3DataWrite(pSSM, &i, sizeof(i));
     3094}
     3095
     3096
     3097/**
     3098 * Saves a GC natural unsigned integer item to the current data unit.
     3099 *
     3100 * @returns VBox status.
     3101 * @param   pSSM            SSM operation handle.
     3102 * @param   u               Item to save.
     3103 *
     3104 * @deprecated Silly type, don't use it.
     3105 */
     3106VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
     3107{
     3108    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3109    return ssmR3DataWrite(pSSM, &u, sizeof(u));
     3110}
     3111
     3112
     3113/**
     3114 * Saves a GC unsigned integer register item to the current data unit.
     3115 *
     3116 * @returns VBox status.
     3117 * @param   pSSM            SSM operation handle.
     3118 * @param   u               Item to save.
     3119 */
     3120VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
     3121{
     3122    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3123    return ssmR3DataWrite(pSSM, &u, sizeof(u));
     3124}
     3125
     3126
     3127/**
     3128 * Saves a 32 bits GC physical address item to the current data unit.
     3129 *
     3130 * @returns VBox status.
     3131 * @param   pSSM            SSM operation handle.
     3132 * @param   GCPhys          The item to save
     3133 */
     3134VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
     3135{
     3136    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3137    return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
     3138}
     3139
     3140
     3141/**
     3142 * Saves a 64 bits GC physical address item to the current data unit.
     3143 *
     3144 * @returns VBox status.
     3145 * @param   pSSM            SSM operation handle.
     3146 * @param   GCPhys          The item to save
     3147 */
     3148VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
     3149{
     3150    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3151    return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
     3152}
     3153
     3154
     3155/**
     3156 * Saves a GC physical address item to the current data unit.
     3157 *
     3158 * @returns VBox status.
     3159 * @param   pSSM            SSM operation handle.
     3160 * @param   GCPhys          The item to save
     3161 */
     3162VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
     3163{
     3164    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3165    return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
     3166}
     3167
     3168
     3169/**
     3170 * Saves a GC virtual address item to the current data unit.
     3171 *
     3172 * @returns VBox status.
     3173 * @param   pSSM            SSM operation handle.
     3174 * @param   GCPtr           The item to save.
     3175 */
     3176VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
     3177{
     3178    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3179    return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
     3180}
     3181
     3182
     3183/**
     3184 * Saves an RC virtual address item to the current data unit.
     3185 *
     3186 * @returns VBox status.
     3187 * @param   pSSM            SSM operation handle.
     3188 * @param   RCPtr           The item to save.
     3189 */
     3190VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
     3191{
     3192    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3193    return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
     3194}
     3195
     3196
     3197/**
     3198 * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
     3199 *
     3200 * @returns VBox status.
     3201 * @param   pSSM            SSM operation handle.
     3202 * @param   GCPtr           The item to save.
     3203 */
     3204VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
     3205{
     3206    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3207    return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
     3208}
     3209
     3210
     3211/**
     3212 * Saves a I/O port address item to the current data unit.
     3213 *
     3214 * @returns VBox status.
     3215 * @param   pSSM            SSM operation handle.
     3216 * @param   IOPort          The item to save.
     3217 */
     3218VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
     3219{
     3220    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3221    return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
     3222}
     3223
     3224
     3225/**
     3226 * Saves a selector item to the current data unit.
     3227 *
     3228 * @returns VBox status.
     3229 * @param   pSSM            SSM operation handle.
     3230 * @param   Sel             The item to save.
     3231 */
     3232VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
     3233{
     3234    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3235    return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
     3236}
     3237
     3238
     3239/**
     3240 * Saves a memory item to the current data unit.
     3241 *
     3242 * @returns VBox status.
     3243 * @param   pSSM            SSM operation handle.
     3244 * @param   pv              Item to save.
     3245 * @param   cb              Size of the item.
     3246 */
     3247VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
     3248{
     3249    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3250    return ssmR3DataWrite(pSSM, pv, cb);
     3251}
     3252
     3253
     3254/**
     3255 * Saves a zero terminated string item to the current data unit.
     3256 *
     3257 * @returns VBox status.
     3258 * @param   pSSM            SSM operation handle.
     3259 * @param   psz             Item to save.
     3260 */
     3261VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
     3262{
     3263    SSM_ASSERT_WRITEABLE_RET(pSSM);
     3264
     3265    size_t cch = strlen(psz);
     3266    if (cch > _1M)
     3267    {
     3268        AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
     3269        return VERR_TOO_MUCH_DATA;
     3270    }
     3271    uint32_t u32 = (uint32_t)cch;
     3272    int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
     3273    if (rc)
     3274        return rc;
     3275    return ssmR3DataWrite(pSSM, psz, cch);
    25463276}
    25473277
     
    29583688
    29593689
    2960 /**
    2961  * Calculate the checksum of a file portion.
    2962  *
    2963  * @returns VBox status.
    2964  * @param   pStrm       The stream handle
    2965  * @param   off         Where to start checksumming.
    2966  * @param   cb          How much to checksum.
    2967  * @param   pu32CRC     Where to store the calculated checksum.
    2968  */
    2969 static int ssmR3CalcChecksum(PSSMSTRM pStrm, uint64_t off, uint64_t cb, uint32_t *pu32CRC)
    2970 {
    2971     /*
    2972      * Allocate a buffer.
    2973      */
    2974     const size_t cbBuf = _32K;
    2975     void *pvBuf = RTMemTmpAlloc(cbBuf);
    2976     if (!pvBuf)
    2977         return VERR_NO_TMP_MEMORY;
    2978 
    2979     /*
    2980      * Loop reading and calculating CRC32.
    2981      */
    2982     int         rc     = VINF_SUCCESS;
    2983     uint32_t    u32CRC = RTCrc32Start();
    2984     while (cb > 0)
    2985     {
    2986         /* read chunk */
    2987         size_t cbToRead = cbBuf;
    2988         if (cb < cbBuf)
    2989             cbToRead = cb;
    2990         rc = ssmR3StrmPeekAt(pStrm, off, pvBuf, cbToRead, NULL);
    2991         if (RT_FAILURE(rc))
    2992         {
    2993             AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
    2994             RTMemTmpFree(pvBuf);
    2995             return rc;
    2996         }
    2997 
    2998         /* advance */
    2999         cb  -= cbToRead;
    3000         off += cbToRead;
    3001 
    3002         /* calc crc32. */
    3003         u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
    3004     }
    3005     RTMemTmpFree(pvBuf);
    3006 
    3007     /* store the calculated crc */
    3008     u32CRC = RTCrc32Finish(u32CRC);
    3009     Log(("SSM: u32CRC=0x%08x\n", u32CRC));
    3010     *pu32CRC = u32CRC;
    3011 
    3012     return VINF_SUCCESS;
    3013 }
    3014 
    3015 
    3016 /**
    3017  * Validates the header information stored in the handle.
    3018  *
    3019  * @returns VBox status code.
    3020  *
    3021  * @param   pSSM            The handle.
    3022  * @param   fHaveHostBits   Set if the host bits field is valid.
    3023  * @param   fHaveVersion    Set if we have a version.
    3024  */
    3025 static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
    3026 {
    3027     Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
    3028     Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
    3029     Assert(pSSM->u.Read.uFmtVerMinor <= 2);
    3030 
    3031     if (fHaveVersion)
    3032     {
    3033         if (    pSSM->u.Read.u16VerMajor == 0
    3034             ||  pSSM->u.Read.u16VerMajor > 1000
    3035             ||  pSSM->u.Read.u16VerMinor > 1000
    3036             ||  pSSM->u.Read.u32VerBuild > _1M
    3037             ||  pSSM->u.Read.u32SvnRev == 0
    3038             ||  pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
    3039         {
    3040             LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
    3041                     pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
    3042             return VERR_SSM_INTEGRITY_VBOX_VERSION;
    3043         }
    3044     }
    3045     else
    3046         AssertLogRelReturn(   pSSM->u.Read.u16VerMajor == 0
    3047                            && pSSM->u.Read.u16VerMinor == 0
    3048                            && pSSM->u.Read.u32VerBuild == 0
    3049                            && pSSM->u.Read.u32SvnRev   == 0,
    3050                            VERR_SSM_INTEGRITY_VBOX_VERSION);
    3051 
    3052     if (fHaveHostBits)
    3053     {
    3054         if (    pSSM->u.Read.cHostBits != 32
    3055             &&  pSSM->u.Read.cHostBits != 64)
    3056         {
    3057             LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
    3058             return VERR_SSM_INTEGRITY_HEADER;
    3059         }
    3060     }
    3061     else
    3062         AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_HEADER);
    3063 
    3064     if (    pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
    3065         &&  pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
    3066     {
    3067         LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
    3068         return VERR_SSM_INTEGRITY_HEADER;
    3069     }
    3070     if (    pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
    3071         &&  pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
    3072     {
    3073         LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
    3074         return VERR_SSM_INTEGRITY_HEADER;
    3075     }
    3076 
    3077     return VINF_SUCCESS;
    3078 }
    3079 
    3080 
    3081 /**
    3082  * Reads the header, detects the format version and performs integrity
    3083  * validations.
    3084  *
    3085  * @returns VBox status.
    3086  * @param   File                File to validate.
    3087  *                              The file position is undefined on return.
    3088  * @param   fChecksumIt         Whether to checksum the file or not.  This will
    3089  *                              be ignored if it the stream isn't a file.
    3090  * @param   fChecksumOnRead     Whether to validate the checksum while reading
    3091  *                              the stream instead of up front. If not possible,
    3092  *                              verify the checksum up front.
    3093  * @param   pHdr                Where to store the file header.
    3094  */
    3095 static int ssmR3HeaderAndValidate(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
    3096 {
    3097     /*
    3098      * Read and check the header magic.
    3099      */
    3100     union
    3101     {
    3102         SSMFILEHDR          v2_0;
    3103         SSMFILEHDRV12       v1_2;
    3104         SSMFILEHDRV11       v1_1;
    3105     } uHdr;
    3106     int rc = ssmR3StrmRead(&pSSM->Strm, &uHdr, sizeof(uHdr.v2_0.szMagic));
    3107     if (RT_FAILURE(rc))
    3108     {
    3109         LogRel(("SSM: Failed to read file magic header. rc=%Rrc\n", rc));
    3110         return rc;
    3111     }
    3112     if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
    3113     {
    3114         Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
    3115         return VERR_SSM_INTEGRITY_MAGIC;
    3116     }
    3117 
    3118     /*
    3119      * Find the header size and read the rest.
    3120      */
    3121     static const struct
    3122     {
    3123         char        szMagic[sizeof(SSMFILEHDR_MAGIC_V2_0)];
    3124         size_t      cbHdr;
    3125         unsigned    uFmtVerMajor;
    3126         unsigned    uFmtVerMinor;
    3127     }   s_aVers[] =
    3128     {
    3129         { SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR),    2, 0 },
    3130         { SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDRV12), 1, 2 },
    3131         { SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDRV11), 1, 1 },
    3132     };
    3133     int iVer = RT_ELEMENTS(s_aVers);
    3134     while (iVer-- > 0)
    3135         if (!memcmp(uHdr.v2_0.szMagic, s_aVers[iVer].szMagic, sizeof(uHdr.v2_0.szMagic)))
    3136             break;
    3137     if (iVer < 0)
    3138     {
    3139         Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
    3140         return VERR_SSM_INTEGRITY_VERSION;
    3141     }
    3142     pSSM->u.Read.uFmtVerMajor   = s_aVers[iVer].uFmtVerMajor;
    3143     pSSM->u.Read.uFmtVerMinor   = s_aVers[iVer].uFmtVerMinor;
    3144     pSSM->u.Read.cbFileHdr      = s_aVers[iVer].cbHdr;
    3145 
    3146     rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)&uHdr + sizeof(uHdr.v2_0.szMagic), pSSM->u.Read.cbFileHdr - sizeof(uHdr.v2_0.szMagic));
    3147     if (RT_FAILURE(rc))
    3148     {
    3149         LogRel(("SSM: Failed to read the file header. rc=%Rrc\n", rc));
    3150         return rc;
    3151     }
    3152 
    3153     /*
    3154      * Make version specific adjustments.
    3155      */
    3156     if (pSSM->u.Read.uFmtVerMajor >= 2)
    3157     {
    3158         /*
    3159          * Version 2.0 and later.
    3160          */
    3161         bool fChecksummed;
    3162         if (pSSM->u.Read.uFmtVerMinor == 0)
    3163         {
    3164             /* validate the header. */
    3165             SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
    3166             if (uHdr.v2_0.u8Reserved)
    3167             {
    3168                 LogRel(("SSM: Reserved header field isn't zero: %02x\n", uHdr.v2_0.u8Reserved));
    3169                 return VERR_SSM_INTEGRITY;
    3170             }
    3171             if ((uHdr.v2_0.fFlags & ~SSMFILEHDR_FLAGS_STREAM_CRC32))
    3172             {
    3173                 LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
    3174                 return VERR_SSM_INTEGRITY;
    3175             }
    3176             if (    uHdr.v2_0.cbMaxDecompr > sizeof(pSSM->u.Read.abDataBuffer)
    3177                 ||  uHdr.v2_0.cbMaxDecompr < _1K
    3178                 ||  (uHdr.v2_0.cbMaxDecompr & 0xff) != 0)
    3179             {
    3180                 LogRel(("SSM: The cbMaxDecompr header field is out of range: %#x\n", uHdr.v2_0.cbMaxDecompr));
    3181                 return VERR_SSM_INTEGRITY;
    3182             }
    3183 
    3184             /* set the header info. */
    3185             pSSM->u.Read.cHostBits      = uHdr.v2_0.cHostBits;
    3186             pSSM->u.Read.u16VerMajor    = uHdr.v2_0.u16VerMajor;
    3187             pSSM->u.Read.u16VerMinor    = uHdr.v2_0.u16VerMinor;
    3188             pSSM->u.Read.u32VerBuild    = uHdr.v2_0.u32VerBuild;
    3189             pSSM->u.Read.u32SvnRev      = uHdr.v2_0.u32SvnRev;
    3190             pSSM->u.Read.cbGCPhys       = uHdr.v2_0.cbGCPhys;
    3191             pSSM->u.Read.cbGCPtr        = uHdr.v2_0.cbGCPtr;
    3192             pSSM->u.Read.fFixedGCPtrSize = true;
    3193             fChecksummed = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
    3194         }
    3195         else
    3196             AssertFailedReturn(VERR_INTERNAL_ERROR);
    3197         if (!fChecksummed)
    3198             ssmR3StrmDisableChecksumming(&pSSM->Strm);
    3199 
    3200         /*
    3201          * Read and validate the footer if it's a file.
    3202          */
    3203         if (ssmR3StrmIsFile(&pSSM->Strm))
    3204         {
    3205             SSMFILEFTR  Footer;
    3206             uint64_t    offFooter;
    3207             rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(SSMFILEFTR), &Footer, sizeof(Footer), &offFooter);
    3208             AssertLogRelRCReturn(rc, rc);
    3209             if (memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)))
    3210             {
    3211                 LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(Footer.szMagic), &Footer.szMagic[0]));
    3212                 return VERR_SSM_INTEGRITY_FOOTER;
    3213             }
    3214             SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
    3215             if (Footer.offStream != offFooter)
    3216             {
    3217                 LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
    3218                 return VERR_SSM_INTEGRITY_FOOTER;
    3219             }
    3220             if (Footer.u32Reserved)
    3221             {
    3222                 LogRel(("SSM: Reserved footer field isn't zero: %08x\n", Footer.u32Reserved));
    3223                 return VERR_SSM_INTEGRITY_FOOTER;
    3224             }
    3225             if (    !fChecksummed
    3226                 &&  Footer.u32StreamCRC)
    3227             {
    3228                 LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
    3229                 return VERR_SSM_INTEGRITY_FOOTER;
    3230             }
    3231 
    3232             pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
    3233             pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
    3234         }
    3235         else
    3236         {
    3237             pSSM->u.Read.cbLoadFile = UINT64_MAX;
    3238             pSSM->u.Read.u32LoadCRC = 0;
    3239         }
    3240 
    3241         /*
    3242          * Validate the header info we've set in the handle.
    3243          */
    3244         rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
    3245         if (RT_FAILURE(rc))
    3246             return rc;
    3247 
    3248         /*
    3249          * Check the checksum if that's called for and possible.
    3250          */
    3251         if (    fChecksummed
    3252             &&  fChecksumIt
    3253             &&  !fChecksumOnRead
    3254             &&  ssmR3StrmIsFile(&pSSM->Strm))
    3255         {
    3256             uint32_t u32CRC;
    3257             rc = ssmR3CalcChecksum(&pSSM->Strm, 0, pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR), &u32CRC);
    3258             if (RT_FAILURE(rc))
    3259                 return rc;
    3260             if (u32CRC != pSSM->u.Read.u32LoadCRC)
    3261             {
    3262                 LogRel(("SSM: Invalid CRC! Calculated %#010x, in footer %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
    3263                 return VERR_SSM_INTEGRITY_CRC;
    3264             }
    3265         }
    3266     }
    3267     else
    3268     {
    3269         /*
    3270          * Version 1.x of the format.
    3271          */
    3272         bool        fHaveHostBits = true;
    3273         bool        fHaveVersion  = false;
    3274         RTUUID      MachineUuidFromHdr;
    3275 
    3276         ssmR3StrmDisableChecksumming(&pSSM->Strm);
    3277         if (pSSM->u.Read.uFmtVerMinor == 1)
    3278         {
    3279             pSSM->u.Read.cHostBits      = 0; /* unknown */
    3280             pSSM->u.Read.u16VerMajor    = 0;
    3281             pSSM->u.Read.u16VerMinor    = 0;
    3282             pSSM->u.Read.u32VerBuild    = 0;
    3283             pSSM->u.Read.u32SvnRev      = 0;
    3284             pSSM->u.Read.cbLoadFile     = uHdr.v1_1.cbFile;
    3285             pSSM->u.Read.u32LoadCRC     = uHdr.v1_1.u32CRC;
    3286             pSSM->u.Read.cbGCPhys       = sizeof(RTGCPHYS);
    3287             pSSM->u.Read.cbGCPtr        = sizeof(RTGCPTR);
    3288             pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
    3289 
    3290             MachineUuidFromHdr  = uHdr.v1_1.MachineUuid;
    3291             fHaveHostBits       = false;
    3292         }
    3293         else if (pSSM->u.Read.uFmtVerMinor == 2)
    3294         {
    3295             pSSM->u.Read.cHostBits      = uHdr.v1_2.cHostBits;
    3296             pSSM->u.Read.u16VerMajor    = uHdr.v1_2.u16VerMajor;
    3297             pSSM->u.Read.u16VerMinor    = uHdr.v1_2.u16VerMinor;
    3298             pSSM->u.Read.u32VerBuild    = uHdr.v1_2.u32VerBuild;
    3299             pSSM->u.Read.u32SvnRev      = uHdr.v1_2.u32SvnRev;
    3300             pSSM->u.Read.cbLoadFile     = uHdr.v1_2.cbFile;
    3301             pSSM->u.Read.u32LoadCRC     = uHdr.v1_2.u32CRC;
    3302             pSSM->u.Read.cbGCPhys       = uHdr.v1_2.cbGCPhys;
    3303             pSSM->u.Read.cbGCPtr        = uHdr.v1_2.cbGCPtr;
    3304             pSSM->u.Read.fFixedGCPtrSize = true;
    3305 
    3306             MachineUuidFromHdr  = uHdr.v1_2.MachineUuid;
    3307             fHaveVersion        = true;
    3308         }
    3309         else
    3310             AssertFailedReturn(VERR_INTERNAL_ERROR);
    3311 
    3312         /*
    3313          * The MachineUuid must be NULL (was never used).
    3314          */
    3315         if (!RTUuidIsNull(&MachineUuidFromHdr))
    3316         {
    3317             LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
    3318             return VERR_SMM_INTEGRITY_MACHINE;
    3319         }
    3320 
    3321         /*
    3322          * Verify the file size.
    3323          */
    3324         uint64_t cbFile = ssmR3StrmGetSize(&pSSM->Strm);
    3325         if (cbFile != pSSM->u.Read.cbLoadFile)
    3326         {
    3327             LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
    3328             return VERR_SSM_INTEGRITY_SIZE;
    3329         }
    3330 
    3331         /*
    3332          * Validate the header info we've set in the handle.
    3333          */
    3334         rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
    3335         if (RT_FAILURE(rc))
    3336             return rc;
    3337 
    3338         /*
    3339          * Verify the checksum if requested.
    3340          *
    3341          * Note! The checksum is not actually generated for the whole file,
    3342          *       this is of course a bug in the v1.x code that we cannot do
    3343          *       anything about.
    3344          */
    3345         if (    fChecksumIt
    3346             ||  fChecksumOnRead)
    3347         {
    3348             uint32_t u32CRC;
    3349             rc = ssmR3CalcChecksum(&pSSM->Strm,
    3350                                    RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC),
    3351                                    cbFile - pSSM->u.Read.cbFileHdr,
    3352                                    &u32CRC);
    3353             if (RT_FAILURE(rc))
    3354                 return rc;
    3355             if (u32CRC != pSSM->u.Read.u32LoadCRC)
    3356             {
    3357                 LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
    3358                 return VERR_SSM_INTEGRITY_CRC;
    3359             }
    3360         }
    3361     }
    3362 
    3363     return VINF_SUCCESS;
    3364 }
    3365 
    3366 
    3367 /**
    3368  * Open a saved state for reading.
    3369  *
    3370  * The file will be positioned at the first data unit upon successful return.
    3371  *
    3372  * @returns VBox status code.
    3373  *
    3374  * @param   pVM                 The VM handle.
    3375  * @param   pszFilename         The filename.
    3376  * @param   fChecksumIt         Check the checksum for the entire file.
    3377  * @param   fChecksumOnRead     Whether to validate the checksum while reading
    3378  *                              the stream instead of up front. If not possible,
    3379  *                              verify the checksum up front.
    3380  * @param   pSSM                Pointer to the handle structure. This will be
    3381  *                              completely initialized on success.
    3382  * @param   cBuffers            The number of stream buffers.
    3383  */
    3384 static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead,
    3385                          uint32_t cBuffers, PSSMHANDLE pSSM)
    3386 {
    3387     /*
    3388      * Initialize the handle.
    3389      */
    3390     pSSM->pVM              = pVM;
    3391     pSSM->enmOp            = SSMSTATE_INVALID;
    3392     pSSM->enmAfter         = SSMAFTER_INVALID;
    3393     pSSM->rc               = VINF_SUCCESS;
    3394     pSSM->cbUnitLeftV1     = 0;
    3395     pSSM->offUnit          = UINT64_MAX;
    3396     pSSM->pfnProgress      = NULL;
    3397     pSSM->pvUser           = NULL;
    3398     pSSM->uPercent         = 0;
    3399     pSSM->offEstProgress   = 0;
    3400     pSSM->cbEstTotal       = 0;
    3401     pSSM->offEst           = 0;
    3402     pSSM->offEstUnitEnd    = 0;
    3403     pSSM->uPercentPrepare  = 5;
    3404     pSSM->uPercentDone     = 2;
    3405 
    3406     pSSM->u.Read.pZipDecompV1   = NULL;
    3407     pSSM->u.Read.uFmtVerMajor   = UINT32_MAX;
    3408     pSSM->u.Read.uFmtVerMinor   = UINT32_MAX;
    3409     pSSM->u.Read.cbFileHdr      = UINT32_MAX;
    3410     pSSM->u.Read.cbGCPhys       = UINT8_MAX;
    3411     pSSM->u.Read.cbGCPtr        = UINT8_MAX;
    3412     pSSM->u.Read.fFixedGCPtrSize= false;
    3413     pSSM->u.Read.u16VerMajor    = UINT16_MAX;
    3414     pSSM->u.Read.u16VerMinor    = UINT16_MAX;
    3415     pSSM->u.Read.u32VerBuild    = UINT32_MAX;
    3416     pSSM->u.Read.u32SvnRev      = UINT32_MAX;
    3417     pSSM->u.Read.cHostBits      = UINT8_MAX;
    3418     pSSM->u.Read.cbLoadFile     = UINT64_MAX;
    3419 
    3420     pSSM->u.Read.cbRecLeft      = 0;
    3421     pSSM->u.Read.cbDataBuffer   = 0;
    3422     pSSM->u.Read.offDataBuffer  = 0;
    3423     pSSM->u.Read.fEndOfData     = 0;
    3424     pSSM->u.Read.u8TypeAndFlags = 0;
    3425 
    3426     /*
    3427      * Try open and validate the file.
    3428      */
    3429     int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, false /*fWrite*/, fChecksumOnRead, cBuffers);
    3430     if (RT_SUCCESS(rc))
    3431     {
    3432         rc = ssmR3HeaderAndValidate(pSSM, fChecksumIt, fChecksumOnRead);
    3433         if (RT_SUCCESS(rc))
    3434             return rc;
    3435 
    3436         /* failure path */
    3437         ssmR3StrmClose(&pSSM->Strm);
    3438     }
    3439     else
    3440         Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n",  pszFilename, rc));
    3441     return rc;
    3442 }
    3443 
    3444 
    3445 /**
    3446  * Find a data unit by name.
    3447  *
    3448  * @returns Pointer to the unit.
    3449  * @returns NULL if not found.
    3450  *
    3451  * @param   pVM             VM handle.
    3452  * @param   pszName         Data unit name.
    3453  * @param   uInstance       The data unit instance id.
    3454  */
    3455 static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t uInstance)
    3456 {
    3457     size_t   cchName = strlen(pszName);
    3458     PSSMUNIT pUnit = pVM->ssm.s.pHead;
    3459     while (     pUnit
    3460            &&   (   pUnit->u32Instance != uInstance
    3461                  || pUnit->cchName != cchName
    3462                  || memcmp(pUnit->szName, pszName, cchName)))
    3463         pUnit = pUnit->pNext;
    3464     return pUnit;
    3465 }
    3466 
    3467 
    3468 /**
    3469  * Executes the loading of a V1.X file.
    3470  *
    3471  * @returns VBox status code.
    3472  * @param   pVM                 The VM handle.
    3473  * @param   pSSM                The saved state handle.
    3474  */
    3475 static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
    3476 {
    3477     int     rc;
    3478     char   *pszName = NULL;
    3479     size_t  cchName = 0;
    3480     pSSM->enmOp = SSMSTATE_LOAD_EXEC;
    3481     for (;;)
    3482     {
    3483         /*
    3484          * Save the current file position and read the data unit header.
    3485          */
    3486         uint64_t         offUnit = ssmR3StrmTell(&pSSM->Strm);
    3487         SSMFILEUNITHDRV1 UnitHdr;
    3488         rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName));
    3489         if (RT_SUCCESS(rc))
    3490         {
    3491             /*
    3492              * Check the magic and see if it's valid and whether it is a end header or not.
    3493              */
    3494             if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
    3495             {
    3496                 if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
    3497                 {
    3498                     Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
    3499                     /* Complete the progress bar (pending 99% afterwards). */
    3500                     ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
    3501                     break;
    3502                 }
    3503                 LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
    3504                         offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
    3505                 rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
    3506                 break;
    3507             }
    3508 
    3509             /*
    3510              * Read the name.
    3511              * Adjust the name buffer first.
    3512              */
    3513             if (cchName < UnitHdr.cchName)
    3514             {
    3515                 if (pszName)
    3516                     RTMemTmpFree(pszName);
    3517                 cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
    3518                 pszName = (char *)RTMemTmpAlloc(cchName);
    3519             }
    3520             if (pszName)
    3521             {
    3522                 rc = ssmR3StrmRead(&pSSM->Strm, pszName, UnitHdr.cchName);
    3523                 if (RT_SUCCESS(rc))
    3524                 {
    3525                     if (pszName[UnitHdr.cchName - 1])
    3526                     {
    3527                         LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
    3528                         rc = VERR_SSM_INTEGRITY_UNIT;
    3529                         break;
    3530                     }
    3531                     Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
    3532 
    3533                     /*
    3534                      * Find the data unit in our internal table.
    3535                      */
    3536                     PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
    3537                     if (pUnit)
    3538                     {
    3539                         /*
    3540                          * Call the execute handler.
    3541                          */
    3542                         pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[UnitHdr.cchName]);
    3543                         pSSM->offUnit = 0;
    3544                         if (!pUnit->u.Common.pfnLoadExec)
    3545                         {
    3546                             LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
    3547                             rc = VERR_SSM_NO_LOAD_EXEC;
    3548                             break;
    3549                         }
    3550                         switch (pUnit->enmType)
    3551                         {
    3552                             case SSMUNITTYPE_DEV:
    3553                                 rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
    3554                                 break;
    3555                             case SSMUNITTYPE_DRV:
    3556                                 rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
    3557                                 break;
    3558                             case SSMUNITTYPE_INTERNAL:
    3559                                 rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
    3560                                 break;
    3561                             case SSMUNITTYPE_EXTERNAL:
    3562                                 rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PHASE_FINAL);
    3563                                 break;
    3564                         }
    3565 
    3566                         /*
    3567                          * Close the reader stream.
    3568                          */
    3569                         ssmR3DataReadFinishV1(pSSM);
    3570 
    3571                         pUnit->fCalled = true;
    3572                         if (RT_SUCCESS(rc))
    3573                             rc = pSSM->rc;
    3574                         if (RT_SUCCESS(rc))
    3575                         {
    3576                             /*
    3577                              * Now, we'll check the current position to see if all, or
    3578                              * more than all, the data was read.
    3579                              *
    3580                              * Note! Because of buffering / compression we'll only see the
    3581                              * really bad ones here.
    3582                              */
    3583                             uint64_t off = ssmR3StrmTell(&pSSM->Strm);
    3584                             int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
    3585                             if (i64Diff < 0)
    3586                             {
    3587                                 Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
    3588                                 rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
    3589                                 ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
    3590                             }
    3591                             else if (i64Diff > 0)
    3592                             {
    3593                                 LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
    3594                                 rc = VMSetError(pVM, VERR_SSM_LOADED_TOO_MUCH, RT_SRC_POS,
    3595                                                 N_("Unit '%s' read %lld bytes too much"), pszName, i64Diff);
    3596                                 break;
    3597                             }
    3598 
    3599                             pSSM->offUnit = UINT64_MAX;
    3600                         }
    3601                         else
    3602                         {
    3603                             LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
    3604                                     pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
    3605                             VMSetError(pVM, rc, RT_SRC_POS, N_("Load exec failed for '%s' instance #%u (version %u)"),
    3606                                        pszName, UnitHdr.u32Instance, UnitHdr.u32Version);
    3607                             break;
    3608                         }
    3609                     }
    3610                     else
    3611                     {
    3612                         /*
    3613                          * SSM unit wasn't found - ignore this when loading for the debugger.
    3614                          */
    3615                         LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
    3616                         rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
    3617                         if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
    3618                             break;
    3619                         rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
    3620                     }
    3621                 }
    3622             }
    3623             else
    3624                 rc = VERR_NO_TMP_MEMORY;
    3625         }
    3626 
    3627         /*
    3628          * I/O errors ends up here (yea, I know, very nice programming).
    3629          */
    3630         if (RT_FAILURE(rc))
    3631         {
    3632             LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
    3633             break;
    3634         }
    3635     }
    3636 
    3637     RTMemTmpFree(pszName);
    3638     return rc;
    3639 }
    3640 
    3641 
    3642 /**
    3643  * Executes the loading of a V2.X file.
    3644  *
    3645  * @returns VBox status code.
    3646  * @param   pVM                 The VM handle.
    3647  * @param   pSSM                The saved state handle.
    3648  */
    3649 static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
    3650 {
    3651     pSSM->enmOp = SSMSTATE_LOAD_EXEC;
    3652     for (;;)
    3653     {
    3654         /*
    3655          * Read the unit header and check its integrity.
    3656          */
    3657         uint64_t            offUnit         = ssmR3StrmTell(&pSSM->Strm);
    3658         uint32_t            u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
    3659         SSMFILEUNITHDRV2    UnitHdr;
    3660         int rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName));
    3661         if (RT_FAILURE(rc))
    3662             return rc;
    3663         if (RT_UNLIKELY(    memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
    3664                         &&  memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END,   sizeof(UnitHdr.szMagic))))
    3665         {
    3666             LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
    3667                     offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
    3668             return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_MAGIC, RT_SRC_POS,
    3669                               N_("Unit at %#llx (%lld): Invalid unit magic"), offUnit, offUnit);
    3670         }
    3671         if (UnitHdr.cbName)
    3672         {
    3673             AssertLogRelMsgReturn(UnitHdr.cbName <= sizeof(UnitHdr.szName),
    3674                                   ("Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
    3675                                    offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)),
    3676                                   VERR_SSM_INTEGRITY_UNIT);
    3677             rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr.szName[0], UnitHdr.cbName);
    3678             if (RT_FAILURE(rc))
    3679                 return rc;
    3680             AssertLogRelMsgReturn(!UnitHdr.szName[UnitHdr.cbName - 1],
    3681                                   ("Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
    3682                                    offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName),
    3683                                   VERR_SSM_INTEGRITY_UNIT);
    3684         }
    3685         SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
    3686                             ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
    3687         AssertLogRelMsgReturn(UnitHdr.offStream == offUnit,
    3688                               ("Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit),
    3689                               VERR_SSM_INTEGRITY_UNIT);
    3690         AssertLogRelMsgReturn(UnitHdr.u32CurStreamCRC == u32CurStreamCRC || !pSSM->Strm.fChecksummed,
    3691                               ("Unit at %#llx (%lld): Stream CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, UnitHdr.u32CurStreamCRC, u32CurStreamCRC),
    3692                               VERR_SSM_INTEGRITY_UNIT);
    3693         AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags),
    3694                               VERR_SSM_INTEGRITY_UNIT);
    3695         if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END,   sizeof(UnitHdr.szMagic)))
    3696         {
    3697             AssertLogRelMsgReturn(   UnitHdr.cbName       == 0
    3698                                   && UnitHdr.u32Instance  == 0
    3699                                   && UnitHdr.u32Version   == 0
    3700                                   && UnitHdr.u32Phase     == SSM_PHASE_FINAL,
    3701                                   ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
    3702                                   VERR_SSM_INTEGRITY_UNIT);
    3703 
    3704             /*
    3705              * Complete the progress bar (pending 99% afterwards) and RETURN.
    3706              */
    3707             Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
    3708             ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
    3709             return VINF_SUCCESS;
    3710         }
    3711         AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
    3712 
    3713         Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
    3714              offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version));
    3715 
    3716         /*
    3717          * Find the data unit in our internal table.
    3718          */
    3719         PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
    3720         if (pUnit)
    3721         {
    3722             /*
    3723              * Call the execute handler.
    3724              */
    3725             AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
    3726                                   ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
    3727                                   VERR_SSM_NO_LOAD_EXEC);
    3728             ssmR3DataReadBeginV2(pSSM);
    3729             switch (pUnit->enmType)
    3730             {
    3731                 case SSMUNITTYPE_DEV:
    3732                     rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
    3733                     break;
    3734                 case SSMUNITTYPE_DRV:
    3735                     rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
    3736                     break;
    3737                 case SSMUNITTYPE_INTERNAL:
    3738                     rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
    3739                     break;
    3740                 case SSMUNITTYPE_EXTERNAL:
    3741                     rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Phase);
    3742                     break;
    3743             }
    3744             ssmR3DataReadFinishV2(pSSM);
    3745             pUnit->fCalled = true;
    3746             if (RT_SUCCESS(rc))
    3747                 rc = pSSM->rc;
    3748             if (RT_SUCCESS(rc))
    3749                 pSSM->offUnit = UINT64_MAX;
    3750             else
    3751             {
    3752                 LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u, phase %#x): %Rrc\n",
    3753                         UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Phase, rc));
    3754                 return VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to load unit '%s'"), UnitHdr.szName);
    3755             }
    3756         }
    3757         else
    3758         {
    3759             /*
    3760              * SSM unit wasn't found - ignore this when loading for the debugger.
    3761              */
    3762             LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
    3763             if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
    3764                 return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_NOT_FOUND, RT_SRC_POS,
    3765                                   N_("Found no handler for unit '%s' instance #%u"), UnitHdr.szName, UnitHdr.u32Instance);
    3766             SSMR3SkipToEndOfUnit(pSSM);
    3767             ssmR3DataReadFinishV2(pSSM);
    3768         }
    3769     }
    3770     /* won't get here */
    3771 }
    3772 
    3773 
    3774 
    3775 
    3776 /**
    3777  * Load VM save operation.
    3778  *
    3779  * @returns VBox status.
    3780  *
    3781  * @param   pVM             The VM handle.
    3782  * @param   pszFilename     Name of the file to save the state in.
    3783  * @param   enmAfter        What is planned after a successful load operation.
    3784  *                          Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
    3785  * @param   pfnProgress     Progress callback. Optional.
    3786  * @param   pvUser          User argument for the progress callback.
    3787  *
    3788  * @thread  EMT
    3789  */
    3790 VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
    3791 {
    3792     LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
    3793     VM_ASSERT_EMT(pVM);
    3794 
    3795     /*
    3796      * Validate input.
    3797      */
    3798     if (    enmAfter != SSMAFTER_RESUME
    3799         &&  enmAfter != SSMAFTER_DEBUG_IT)
    3800     {
    3801         AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
    3802         return VERR_INVALID_PARAMETER;
    3803     }
    3804 
    3805     /*
    3806      * Create the handle and open the file.
    3807      */
    3808     SSMHANDLE Handle;
    3809     int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, 8 /*cBuffers*/, &Handle);
    3810     if (RT_SUCCESS(rc))
    3811     {
    3812         ssmR3StrmStartIoThread(&Handle.Strm);
    3813 
    3814         Handle.enmAfter     = enmAfter;
    3815         Handle.pfnProgress  = pfnProgress;
    3816         Handle.pvUser       = pvUser;
    3817 
    3818         if (Handle.u.Read.u16VerMajor)
    3819             LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
    3820                     Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
    3821                     Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
    3822                     Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
    3823         else
    3824             LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
    3825                     Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
    3826                     Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
    3827 
    3828         if (pfnProgress)
    3829             pfnProgress(pVM, Handle.uPercent, pvUser);
    3830 
    3831         /*
    3832          * Clear the per unit flags.
    3833          */
    3834         PSSMUNIT pUnit;
    3835         for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
    3836             pUnit->fCalled = false;
    3837 
    3838         /*
    3839          * Do the prepare run.
    3840          */
    3841         Handle.rc = VINF_SUCCESS;
    3842         Handle.enmOp = SSMSTATE_LOAD_PREP;
    3843         for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
    3844         {
    3845             if (pUnit->u.Common.pfnLoadPrep)
    3846             {
    3847                 pUnit->fCalled = true;
    3848                 switch (pUnit->enmType)
    3849                 {
    3850                     case SSMUNITTYPE_DEV:
    3851                         rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
    3852                         break;
    3853                     case SSMUNITTYPE_DRV:
    3854                         rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
    3855                         break;
    3856                     case SSMUNITTYPE_INTERNAL:
    3857                         rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
    3858                         break;
    3859                     case SSMUNITTYPE_EXTERNAL:
    3860                         rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
    3861                         break;
    3862                 }
    3863                 if (RT_FAILURE(rc))
    3864                 {
    3865                     LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
    3866                     break;
    3867                 }
    3868             }
    3869         }
    3870 
    3871         /* pending 2% */
    3872         if (pfnProgress)
    3873             pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
    3874         Handle.uPercent      = Handle.uPercentPrepare;
    3875         Handle.cbEstTotal    = Handle.u.Read.cbLoadFile;
    3876         Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
    3877 
    3878         /*
    3879          * Do the execute run.
    3880          */
    3881         if (RT_SUCCESS(rc))
    3882         {
    3883             if (Handle.u.Read.uFmtVerMajor >= 2)
    3884                 rc = ssmR3LoadExecV2(pVM, &Handle);
    3885             else
    3886                 rc = ssmR3LoadExecV1(pVM, &Handle);
    3887             /* (progress should be pending 99% now) */
    3888             AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
    3889         }
    3890 
    3891         /*
    3892          * Do the done run.
    3893          */
    3894         Handle.rc = rc;
    3895         Handle.enmOp = SSMSTATE_LOAD_DONE;
    3896         for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
    3897         {
    3898             if (    pUnit->u.Common.pfnLoadDone
    3899                 && (   pUnit->fCalled
    3900                     || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
    3901             {
    3902                 rc = VINF_SUCCESS;
    3903                 switch (pUnit->enmType)
    3904                 {
    3905                     case SSMUNITTYPE_DEV:
    3906                         rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
    3907                         break;
    3908                     case SSMUNITTYPE_DRV:
    3909                         rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
    3910                         break;
    3911                     case SSMUNITTYPE_INTERNAL:
    3912                         rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
    3913                         break;
    3914                     case SSMUNITTYPE_EXTERNAL:
    3915                         rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
    3916                         break;
    3917                 }
    3918                 if (RT_FAILURE(rc))
    3919                 {
    3920                     LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
    3921                             rc, pUnit->szName, pUnit->u32Instance));
    3922                     if (RT_SUCCESS(Handle.rc))
    3923                         Handle.rc = rc;
    3924                 }
    3925             }
    3926         }
    3927         rc = Handle.rc;
    3928 
    3929         /* progress */
    3930         if (pfnProgress)
    3931             pfnProgress(pVM, 99, pvUser);
    3932 
    3933         ssmR3StrmClose(&Handle.Strm);
    3934     }
    3935 
    3936     /*
    3937      * Done
    3938      */
    3939     if (RT_SUCCESS(rc))
    3940     {
    3941         /* progress */
    3942         if (pfnProgress)
    3943             pfnProgress(pVM, 100, pvUser);
    3944         Log(("SSM: Load of '%s' completed!\n", pszFilename));
    3945     }
    3946     return rc;
    3947 }
    3948 
    3949 
    3950 /**
    3951  * Validates a file as a validate SSM saved state.
    3952  *
    3953  * This will only verify the file format, the format and content of individual
    3954  * data units are not inspected.
    3955  *
    3956  * @returns VINF_SUCCESS if valid.
    3957  * @returns VBox status code on other failures.
    3958  *
    3959  * @param   pszFilename     The path to the file to validate.
    3960  * @param   fChecksumIt     Whether to checksum the file or not.
    3961  *
    3962  * @thread  Any.
    3963  */
    3964 VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
    3965 {
    3966     LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
    3967 
    3968     /*
    3969      * Try open the file and validate it.
    3970      */
    3971     SSMHANDLE Handle;
    3972     int rc = ssmR3OpenFile(NULL, pszFilename, fChecksumIt, false /*fChecksumOnRead*/, 1 /*cBuffers*/, &Handle);
    3973     if (RT_SUCCESS(rc))
    3974         ssmR3StrmClose(&Handle.Strm);
    3975     else
    3976         Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
    3977     return rc;
    3978 }
    3979 
    3980 
    3981 /**
    3982  * Opens a saved state file for reading.
    3983  *
    3984  * @returns VBox status code.
    3985  *
    3986  * @param   pszFilename     The path to the saved state file.
    3987  * @param   fFlags          Open flags. Reserved, must be 0.
    3988  * @param   ppSSM           Where to store the SSM handle.
    3989  *
    3990  * @thread  Any.
    3991  */
    3992 VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
    3993 {
    3994     LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
    3995 
    3996     /*
    3997      * Validate input.
    3998      */
    3999     AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
    4000     AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
    4001     AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
    4002 
    4003     /*
    4004      * Allocate a handle.
    4005      */
    4006     PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
    4007     AssertReturn(pSSM, VERR_NO_MEMORY);
    4008 
    4009     /*
    4010      * Try open the file and validate it.
    4011      */
    4012     int rc = ssmR3OpenFile(NULL, pszFilename, false /*fChecksumIt*/, true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
    4013     if (RT_SUCCESS(rc))
    4014     {
    4015         pSSM->enmAfter = SSMAFTER_OPENED;
    4016         pSSM->enmOp    = SSMSTATE_OPEN_READ;
    4017         *ppSSM = pSSM;
    4018         LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
    4019         return VINF_SUCCESS;
    4020     }
    4021 
    4022     Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
    4023     RTMemFree(pSSM);
    4024     return rc;
    4025 
    4026 }
    4027 
    4028 
    4029 /**
    4030  * Closes a saved state file opened by SSMR3Open().
    4031  *
    4032  * @returns VBox status code.
    4033  *
    4034  * @param   pSSM            The SSM handle returned by SSMR3Open().
    4035  *
    4036  * @thread  Any, but the caller is responsible for serializing calls per handle.
    4037  */
    4038 VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
    4039 {
    4040     LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
    4041 
    4042     /*
    4043      * Validate input.
    4044      */
    4045     AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
    4046     AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
    4047     AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
    4048 
    4049     /*
    4050      * Close the stream and free the handle.
    4051      */
    4052     int rc = ssmR3StrmClose(&pSSM->Strm);
    4053     if (pSSM->u.Read.pZipDecompV1)
    4054     {
    4055         RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
    4056         pSSM->u.Read.pZipDecompV1 = NULL;
    4057     }
    4058     RTMemFree(pSSM);
    4059     return rc;
    4060 }
    4061 
    4062 
    4063 /**
    4064  * Worker for SSMR3Seek that seeks version 1 saved state files.
    4065  *
    4066  * @returns VBox status code.
    4067  * @param   pSSM                The SSM handle.
    4068  * @param   pszUnit             The unit to seek to.
    4069  * @param   iInstance           The particulart insance we seek.
    4070  * @param   piVersion           Where to store the unit version number.
    4071  */
    4072 static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
    4073 {
    4074     /*
    4075      * Walk the data units until we find EOF or a match.
    4076      */
    4077     size_t              cbUnitNm = strlen(pszUnit) + 1;
    4078     AssertLogRelReturn(cbUnitNm <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
    4079     char                szName[SSM_MAX_NAME_SIZE];
    4080     SSMFILEUNITHDRV1    UnitHdr;
    4081     for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
    4082     {
    4083         /*
    4084          * Read the unit header and verify it.
    4085          */
    4086         int rc = ssmR3StrmPeekAt(&pSSM->Strm, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName), NULL);
    4087         AssertRCReturn(rc, rc);
    4088         if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
    4089         {
    4090             /*
    4091              * Does what we've got match, if so read the name.
    4092              */
    4093             if (    UnitHdr.u32Instance == iInstance
    4094                 &&  UnitHdr.cchName     == cbUnitNm)
    4095             {
    4096                 rc = ssmR3StrmPeekAt(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName), szName, cbUnitNm, NULL);
    4097                 AssertRCReturn(rc, rc);
    4098                 AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
    4099                                       (" Unit name '%.*s' was not properly terminated.\n", cbUnitNm, szName),
    4100                                       VERR_SSM_INTEGRITY_UNIT);
    4101 
    4102                 /*
    4103                  * Does the name match?
    4104                  */
    4105                 if (!memcmp(szName, pszUnit, cbUnitNm))
    4106                 {
    4107                     rc = ssmR3StrmSeek(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName) + cbUnitNm, RTFILE_SEEK_BEGIN, 0);
    4108                     pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[cbUnitNm]);
    4109                     pSSM->offUnit = 0;
    4110                     if (piVersion)
    4111                         *piVersion = UnitHdr.u32Version;
    4112                     return VINF_SUCCESS;
    4113                 }
    4114             }
    4115         }
    4116         else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
    4117             return VERR_SSM_UNIT_NOT_FOUND;
    4118         else
    4119             AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
    4120                                          off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
    4121                                         VERR_SSM_INTEGRITY_UNIT_MAGIC);
    4122     }
    4123     /* won't get here. */
    4124 }
    4125 
    4126 
    4127 /**
    4128  * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
    4129  *
    4130  * @returns VBox status code.
    4131  * @param   pSSM                The SSM handle.
    4132  * @param   pDir                The directory buffer.
    4133  * @param   cbDir               The size of the directory.
    4134  * @param   cDirEntries         The number of directory entries.
    4135  * @param   offDir              The directory offset in the file.
    4136  * @param   pszUnit             The unit to seek to.
    4137  * @param   iInstance           The particulart insance we seek.
    4138  * @param   piVersion           Where to store the unit version number.
    4139  */
    4140 static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries, uint64_t offDir,
    4141                               const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
    4142 {
    4143     /*
    4144      * Read it.
    4145      */
    4146     int rc = ssmR3StrmPeekAt(&pSSM->Strm, offDir, pDir, cbDir, NULL);
    4147     AssertLogRelRCReturn(rc, rc);
    4148     AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY_DIR_MAGIC);
    4149     SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
    4150     AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
    4151                           ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
    4152                            VERR_SSM_INTEGRITY_DIR);
    4153     for (uint32_t i = 0; i < cDirEntries; i++)
    4154         AssertLogRelMsgReturn(pDir->aEntries[i].off < offDir,
    4155                               ("i=%u off=%lld offDir=%lld\n", i, pDir->aEntries[i].off, offDir),
    4156                               VERR_SSM_INTEGRITY_DIR);
    4157 
    4158     /*
    4159      * Search the directory.
    4160      */
    4161     size_t          cbUnitNm   = strlen(pszUnit) + 1;
    4162     uint32_t const  u32NameCRC = RTCrc32(pszUnit, cbUnitNm - 1);
    4163     for (uint32_t i = 0; i < cDirEntries; i++)
    4164     {
    4165         if (    pDir->aEntries[i].u32NameCRC  == u32NameCRC
    4166             &&  pDir->aEntries[i].u32Instance == iInstance)
    4167         {
    4168             /*
    4169              * Read and validate the unit header.
    4170              */
    4171             SSMFILEUNITHDRV2    UnitHdr;
    4172             size_t              cbToRead = sizeof(UnitHdr);
    4173             if (pDir->aEntries[i].off + cbToRead > offDir)
    4174             {
    4175                 cbToRead = offDir - pDir->aEntries[i].off;
    4176                 RT_ZERO(UnitHdr);
    4177             }
    4178             rc = ssmR3StrmPeekAt(&pSSM->Strm, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
    4179             AssertLogRelRCReturn(rc, rc);
    4180 
    4181             AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
    4182                                   ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
    4183                                   VERR_SSM_INTEGRITY_UNIT);
    4184             AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
    4185                                   ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
    4186                                   VERR_SSM_INTEGRITY_UNIT);
    4187             AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
    4188                                   ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
    4189                                    i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
    4190                                   VERR_SSM_INTEGRITY_UNIT);
    4191             uint32_t cbUnitHdr = RT_UOFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]);
    4192             AssertLogRelMsgReturn(   UnitHdr.cbName > 0
    4193                                   && UnitHdr.cbName < sizeof(UnitHdr)
    4194                                   && cbUnitHdr <= cbToRead,
    4195                                   ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
    4196                                   VERR_SSM_INTEGRITY_UNIT);
    4197             SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
    4198                                 ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
    4199                                  i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
    4200 
    4201             /*
    4202              * Ok, it is valid, get on with the comparing now.
    4203              */
    4204             if (    UnitHdr.cbName == cbUnitNm
    4205                 &&  !memcmp(UnitHdr.szName, pszUnit, cbUnitNm))
    4206             {
    4207                 if (piVersion)
    4208                     *piVersion = UnitHdr.u32Version;
    4209                 rc = ssmR3StrmSeek(&pSSM->Strm, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN,
    4210                                    RTCrc32Process(UnitHdr.u32CurStreamCRC, &UnitHdr, cbUnitHdr));
    4211                 AssertLogRelRCReturn(rc, rc);
    4212                 ssmR3DataReadBeginV2(pSSM);
    4213                 return VINF_SUCCESS;
    4214             }
    4215         }
    4216     }
    4217 
    4218     return VERR_SSM_UNIT_NOT_FOUND;
    4219 }
    4220 
    4221 
    4222 /**
    4223  * Worker for SSMR3Seek that seeks version 2 saved state files.
    4224  *
    4225  * @returns VBox status code.
    4226  * @param   pSSM                The SSM handle.
    4227  * @param   pszUnit             The unit to seek to.
    4228  * @param   iInstance           The particulart insance we seek.
    4229  * @param   piVersion           Where to store the unit version number.
    4230  */
    4231 static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
    4232 {
    4233     /*
    4234      * Read the footer, allocate a temporary buffer for the dictionary and
    4235      * pass it down to a worker to simplify cleanup.
    4236      */
    4237     uint64_t        offFooter;
    4238     SSMFILEFTR      Footer;
    4239     int rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(Footer), &Footer, sizeof(Footer), &offFooter);
    4240     AssertLogRelRCReturn(rc, rc);
    4241     AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
    4242     SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
    4243 
    4244     size_t const    cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[Footer.cDirEntries]);
    4245     PSSMFILEDIR     pDir  = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
    4246     if (RT_UNLIKELY(!pDir))
    4247         return VERR_NO_TMP_MEMORY;
    4248     rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, offFooter - cbDir,
    4249                             pszUnit, iInstance, piVersion);
    4250     RTMemTmpFree(pDir);
    4251 
    4252     return rc;
    4253 }
    4254 
    4255 
    4256 
    4257 /**
    4258  * Seeks to a specific data unit.
    4259  *
    4260  * After seeking it's possible to use the getters to on
    4261  * that data unit.
    4262  *
    4263  * @returns VBox status code.
    4264  * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
    4265  *
    4266  * @param   pSSM            The SSM handle returned by SSMR3Open().
    4267  * @param   pszUnit         The name of the data unit.
    4268  * @param   iInstance       The instance number.
    4269  * @param   piVersion       Where to store the version number. (Optional)
    4270  *
    4271  * @thread  Any, but the caller is responsible for serializing calls per handle.
    4272  */
    4273 VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
    4274 {
    4275     LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
    4276              pSSM, pszUnit, pszUnit, iInstance, piVersion));
    4277 
    4278     /*
    4279      * Validate input.
    4280      */
    4281     AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
    4282     AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
    4283     AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
    4284     AssertMsgReturn(VALID_PTR(pszUnit), ("%p\n", pszUnit), VERR_INVALID_POINTER);
    4285     AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
    4286 
    4287     /*
    4288      * Reset the state.
    4289      */
    4290     if (pSSM->u.Read.pZipDecompV1)
    4291     {
    4292         RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
    4293         pSSM->u.Read.pZipDecompV1 = NULL;
    4294     }
    4295     pSSM->cbUnitLeftV1  = 0;
    4296     pSSM->offUnit       = UINT64_MAX;
    4297 
    4298     /*
    4299      * Call the version specific workers.
    4300      */
    4301     if (pSSM->u.Read.uFmtVerMajor >= 2)
    4302         pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
    4303     else
    4304         pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
    4305     return pSSM->rc;
    4306 }
    4307 
    4308 
    4309 /**
    4310  * Finishes a data unit.
    4311  * All buffers and compressor instances are flushed and destroyed.
    4312  *
    4313  * @returns VBox status.
    4314  * @param   pSSM            SSM operation handle.
    4315  */
    4316 static int ssmR3DataWriteFinish(PSSMHANDLE pSSM)
    4317 {
    4318     //Log2(("ssmR3DataWriteFinish: %#010llx start\n", ssmR3StrmTell(&pSSM->Strm)));
    4319     int rc = ssmR3DataFlushBuffer(pSSM);
    4320     if (RT_SUCCESS(rc))
    4321         return VINF_SUCCESS;
    4322 
    4323     if (RT_SUCCESS(pSSM->rc))
    4324         pSSM->rc = rc;
    4325     Log2(("ssmR3DataWriteFinish: failure rc=%Rrc\n", rc));
    4326     return rc;
    4327 }
    4328 
    4329 
    4330 /**
    4331  * Begins writing the data of a data unit.
    4332  *
    4333  * Errors are signalled via pSSM->rc.
    4334  *
    4335  * @param   pSSM            The saved state handle.
    4336  */
    4337 static void ssmR3DataWriteBegin(PSSMHANDLE pSSM)
    4338 {
    4339     pSSM->offUnit = 0;
    4340 }
    4341 
    4342 
    4343 /**
    4344  * Writes a record to the current data item in the saved state file.
    4345  *
    4346  * @returns VBox status code. Sets pSSM->rc on failure.
    4347  * @param   pSSM            The saved state handle.
    4348  * @param   pvBuf           The bits to write.
    4349  * @param   cbBuf           The number of bytes to write.
    4350  */
    4351 static int ssmR3DataWriteRaw(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
    4352 {
    4353     Log2(("ssmR3DataWriteRaw: %08llx|%08llx: pvBuf=%p cbBuf=%#x %.*Rhxs%s\n",
    4354           ssmR3StrmTell(&pSSM->Strm), pSSM->offUnit, pvBuf, cbBuf, RT_MIN(cbBuf, SSM_LOG_BYTES), pvBuf, cbBuf > SSM_LOG_BYTES ? "..." : ""));
    4355 
    4356     /*
    4357      * Check that everything is fine.
    4358      */
    4359     if (RT_FAILURE(pSSM->rc))
    4360         return pSSM->rc;
    4361 
    4362     /*
    4363      * Write the data item in 1MB chunks for progress indicator reasons.
    4364      */
    4365     while (cbBuf > 0)
    4366     {
    4367         size_t cbChunk = RT_MIN(cbBuf, _1M);
    4368         int rc = ssmR3StrmWrite(&pSSM->Strm, pvBuf, cbChunk);
    4369         if (RT_FAILURE(rc))
    4370             return rc;
    4371         pSSM->offUnit += cbChunk;
    4372         cbBuf -= cbChunk;
    4373         pvBuf = (char *)pvBuf + cbChunk;
    4374     }
    4375 
    4376     return VINF_SUCCESS;
    4377 }
    4378 
    4379 
    4380 /**
    4381  * Writes a record header for the specified amount of data.
    4382  *
    4383  * @returns VBox status code. Sets pSSM->rc on failure.
    4384  * @param   pSSM            The saved state handle
    4385  * @param   cb              The amount of data.
    4386  * @param   u8TypeAndFlags  The record type and flags.
    4387  */
    4388 static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
    4389 {
    4390     size_t  cbHdr;
    4391     uint8_t abHdr[8];
    4392     abHdr[0] = u8TypeAndFlags;
    4393     if (cb < 0x80)
    4394     {
    4395         cbHdr = 2;
    4396         abHdr[1] = (uint8_t)cb;
    4397     }
    4398     else if (cb < 0x00000800)
    4399     {
    4400         cbHdr = 3;
    4401         abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
    4402         abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
    4403     }
    4404     else if (cb < 0x00010000)
    4405     {
    4406         cbHdr = 4;
    4407         abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
    4408         abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
    4409         abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
    4410     }
    4411     else if (cb < 0x00200000)
    4412     {
    4413         cbHdr = 5;
    4414         abHdr[1] = (uint8_t)(0xf0 |  (cb >> 18));
    4415         abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
    4416         abHdr[3] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
    4417         abHdr[4] = (uint8_t)(0x80 |  (cb        & 0x3f));
    4418     }
    4419     else if (cb < 0x04000000)
    4420     {
    4421         cbHdr = 6;
    4422         abHdr[1] = (uint8_t)(0xf8 |  (cb >> 24));
    4423         abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
    4424         abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
    4425         abHdr[4] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
    4426         abHdr[5] = (uint8_t)(0x80 |  (cb        & 0x3f));
    4427     }
    4428     else if (cb <= 0x7fffffff)
    4429     {
    4430         cbHdr = 7;
    4431         abHdr[1] = (uint8_t)(0xfc |  (cb >> 30));
    4432         abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
    4433         abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
    4434         abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
    4435         abHdr[5] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
    4436         abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
    4437     }
    4438     else
    4439         AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_INTERNAL_ERROR);
    4440 
    4441     Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
    4442           ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));
    4443 
    4444     return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
    4445 }
    4446 
    4447 
    4448 /**
    4449  * Worker that flushes the buffered data.
    4450  *
    4451  * @returns VBox status code. Will set pSSM->rc on error.
    4452  * @param   pSSM            The saved state handle.
    4453  */
    4454 static int ssmR3DataFlushBuffer(PSSMHANDLE pSSM)
    4455 {
    4456     /*
    4457      * Check how much there current is in the buffer.
    4458      */
    4459     uint32_t cb = pSSM->u.Write.offDataBuffer;
    4460     if (!cb)
    4461         return pSSM->rc;
    4462     pSSM->u.Write.offDataBuffer = 0;
    4463 
    4464     /*
    4465      * Write a record header and then the data.
    4466      * (No need for fancy optimizations here any longer since the stream is
    4467      * fully buffered.)
    4468      */
    4469     int rc = ssmR3DataWriteRecHdr(pSSM, cb, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
    4470     if (RT_SUCCESS(rc))
    4471         rc = ssmR3DataWriteRaw(pSSM, pSSM->u.Write.abDataBuffer, cb);
    4472     ssmR3Progress(pSSM, cb);
    4473     return rc;
    4474 }
    4475 
    4476 
    4477 /**
    4478  * ssmR3DataWrite worker that writes big stuff.
    4479  *
    4480  * @returns VBox status code
    4481  * @param   pSSM            The saved state handle.
    4482  * @param   pvBuf           The bits to write.
    4483  * @param   cbBuf           The number of bytes to write.
    4484  */
    4485 static int ssmR3DataWriteBig(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
    4486 {
    4487     int rc = ssmR3DataFlushBuffer(pSSM);
    4488     if (RT_SUCCESS(rc))
    4489     {
    4490         /*
    4491          * Split it up into compression blocks.
    4492          */
    4493         for (;;)
    4494         {
    4495             AssertCompile(SSM_ZIP_BLOCK_SIZE == PAGE_SIZE);
    4496             if (    cbBuf >= SSM_ZIP_BLOCK_SIZE
    4497                 && (    ((uintptr_t)pvBuf & 0xf)
    4498                     ||  !ASMMemIsZeroPage(pvBuf))
    4499                )
    4500             {
    4501                 /*
    4502                  * Compress it.
    4503                  */
    4504                 AssertCompile(1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE < 0x00010000);
    4505                 uint8_t *pb;
    4506                 rc = ssmR3StrmReserveWriteBufferSpace(&pSSM->Strm, 1 + 3 + 1 + SSM_ZIP_BLOCK_SIZE, &pb);
    4507                 if (RT_FAILURE(rc))
    4508                     break;
    4509                 size_t cbRec = SSM_ZIP_BLOCK_SIZE - (SSM_ZIP_BLOCK_SIZE / 16);
    4510                 rc = RTZipBlockCompress(RTZIPTYPE_LZF, RTZIPLEVEL_FAST, 0 /*fFlags*/,
    4511                                         pvBuf, SSM_ZIP_BLOCK_SIZE,
    4512                                         pb + 1 + 3 + 1, cbRec, &cbRec);
    4513                 if (RT_SUCCESS(rc))
    4514                 {
    4515                     pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_LZF;
    4516                     pb[4] = SSM_ZIP_BLOCK_SIZE / _1K;
    4517                     cbRec += 1;
    4518                 }
    4519                 else
    4520                 {
    4521                     pb[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW;
    4522                     memcpy(&pb[4], pvBuf, SSM_ZIP_BLOCK_SIZE);
    4523                     cbRec = SSM_ZIP_BLOCK_SIZE;
    4524                 }
    4525                 pb[1] = (uint8_t)(0xe0 | ( cbRec >> 12));
    4526                 pb[2] = (uint8_t)(0x80 | ((cbRec >>  6) & 0x3f));
    4527                 pb[3] = (uint8_t)(0x80 | ( cbRec        & 0x3f));
    4528                 cbRec += 1 + 3;
    4529                 rc = ssmR3StrmCommitWriteBufferSpace(&pSSM->Strm, cbRec);
    4530                 if (RT_FAILURE(rc))
    4531                     break;
    4532 
    4533                 pSSM->offUnit += cbRec;
    4534                 ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
    4535 
    4536                 /* advance */
    4537                 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
    4538                     return VINF_SUCCESS;
    4539                 cbBuf -= SSM_ZIP_BLOCK_SIZE;
    4540                 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
    4541             }
    4542             else if (cbBuf >= SSM_ZIP_BLOCK_SIZE)
    4543             {
    4544                 /*
    4545                  * Zero block.
    4546                  */
    4547                 uint8_t abRec[3];
    4548                 abRec[0] = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW_ZERO;
    4549                 abRec[1] = 1;
    4550                 abRec[2] = SSM_ZIP_BLOCK_SIZE / _1K;
    4551                 Log3(("ssmR3DataWriteBig: %08llx|%08llx/%08x: ZERO\n", ssmR3StrmTell(&pSSM->Strm) + 2, pSSM->offUnit + 2, 1));
    4552                 rc = ssmR3DataWriteRaw(pSSM, &abRec[0], sizeof(abRec));
    4553                 if (RT_FAILURE(rc))
    4554                     break;
    4555 
    4556                 /* advance */
    4557                 ssmR3Progress(pSSM, SSM_ZIP_BLOCK_SIZE);
    4558                 if (cbBuf == SSM_ZIP_BLOCK_SIZE)
    4559                     return VINF_SUCCESS;
    4560                 cbBuf -= SSM_ZIP_BLOCK_SIZE;
    4561                 pvBuf = (uint8_t const*)pvBuf + SSM_ZIP_BLOCK_SIZE;
    4562             }
    4563             else
    4564             {
    4565                 /*
    4566                  * Less than one block left, store it the simple way.
    4567                  */
    4568                 rc = ssmR3DataWriteRecHdr(pSSM, cbBuf, SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_RAW);
    4569                 if (RT_SUCCESS(rc))
    4570                     rc = ssmR3DataWriteRaw(pSSM, pvBuf, cbBuf);
    4571                 ssmR3Progress(pSSM, cbBuf);
    4572                 break;
    4573             }
    4574         }
    4575     }
    4576     return rc;
    4577 }
    4578 
    4579 
    4580 /**
    4581  * ssmR3DataWrite worker that is called when there isn't enough room in the
    4582  * buffer for the current chunk of data.
    4583  *
    4584  * This will first flush the buffer and then add the new bits to it.
    4585  *
    4586  * @returns VBox status code
    4587  * @param   pSSM            The saved state handle.
    4588  * @param   pvBuf           The bits to write.
    4589  * @param   cbBuf           The number of bytes to write.
    4590  */
    4591 static int ssmR3DataWriteFlushAndBuffer(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
    4592 {
    4593     int rc = ssmR3DataFlushBuffer(pSSM);
    4594     if (RT_SUCCESS(rc))
    4595     {
    4596         memcpy(&pSSM->u.Write.abDataBuffer[0], pvBuf, cbBuf);
    4597         pSSM->u.Write.offDataBuffer = (uint32_t)cbBuf;
    4598     }
    4599     return rc;
    4600 }
    4601 
    4602 
    4603 /**
    4604  * Writes data to the current data unit.
    4605  *
    4606  * This is an inlined wrapper that optimizes the small writes that so many of
    4607  * the APIs make.
    4608  *
    4609  * @returns VBox status code
    4610  * @param   pSSM            The saved state handle.
    4611  * @param   pvBuf           The bits to write.
    4612  * @param   cbBuf           The number of bytes to write.
    4613  */
    4614 DECLINLINE(int) ssmR3DataWrite(PSSMHANDLE pSSM, const void *pvBuf, size_t cbBuf)
    4615 {
    4616     if (cbBuf > sizeof(pSSM->u.Write.abDataBuffer) / 8)
    4617         return ssmR3DataWriteBig(pSSM, pvBuf, cbBuf);
    4618     if (!cbBuf)
    4619         return VINF_SUCCESS;
    4620 
    4621     uint32_t off = pSSM->u.Write.offDataBuffer;
    4622     if (RT_UNLIKELY(cbBuf + off > sizeof(pSSM->u.Write.abDataBuffer)))
    4623         return ssmR3DataWriteFlushAndBuffer(pSSM, pvBuf, cbBuf);
    4624 
    4625     memcpy(&pSSM->u.Write.abDataBuffer[off], pvBuf, cbBuf);
    4626     pSSM->u.Write.offDataBuffer = off + (uint32_t)cbBuf;
    4627     return VINF_SUCCESS;
    4628 }
    4629 
    4630 
    4631 /**
    4632  * Puts a structure.
    4633  *
    4634  * @returns VBox status code.
    4635  * @param   pSSM            The saved state handle.
    4636  * @param   pvStruct        The structure address.
    4637  * @param   paFields        The array of structure fields descriptions.
    4638  *                          The array must be terminated by a SSMFIELD_ENTRY_TERM().
    4639  */
    4640 VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)
    4641 {
    4642     /* begin marker. */
    4643     int rc = SSMR3PutU32(pSSM, SSMR3STRUCT_BEGIN);
    4644     if (RT_FAILURE(rc))
    4645         return rc;
    4646 
    4647     /* put the fields */
    4648     for (PCSSMFIELD pCur = paFields;
    4649          pCur->cb != UINT32_MAX && pCur->off != UINT32_MAX;
    4650          pCur++)
    4651     {
    4652         rc = ssmR3DataWrite(pSSM, (uint8_t *)pvStruct + pCur->off, pCur->cb);
    4653         if (RT_FAILURE(rc))
    4654             return rc;
    4655     }
    4656 
    4657     /* end marker */
    4658     return SSMR3PutU32(pSSM, SSMR3STRUCT_END);
    4659 }
    4660 
    4661 
    4662 /**
    4663  * Saves a boolean item to the current data unit.
    4664  *
    4665  * @returns VBox status.
    4666  * @param   pSSM            SSM operation handle.
    4667  * @param   fBool           Item to save.
    4668  */
    4669 VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool)
    4670 {
    4671     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4672     uint8_t u8 = fBool; /* enforce 1 byte size */
    4673     return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
    4674 }
    4675 
    4676 
    4677 /**
    4678  * Saves a 8-bit unsigned integer item to the current data unit.
    4679  *
    4680  * @returns VBox status.
    4681  * @param   pSSM            SSM operation handle.
    4682  * @param   u8              Item to save.
    4683  */
    4684 VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8)
    4685 {
    4686     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4687     return ssmR3DataWrite(pSSM, &u8, sizeof(u8));
    4688 }
    4689 
    4690 
    4691 /**
    4692  * Saves a 8-bit signed integer item to the current data unit.
    4693  *
    4694  * @returns VBox status.
    4695  * @param   pSSM            SSM operation handle.
    4696  * @param   i8              Item to save.
    4697  */
    4698 VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8)
    4699 {
    4700     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4701     return ssmR3DataWrite(pSSM, &i8, sizeof(i8));
    4702 }
    4703 
    4704 
    4705 /**
    4706  * Saves a 16-bit unsigned integer item to the current data unit.
    4707  *
    4708  * @returns VBox status.
    4709  * @param   pSSM            SSM operation handle.
    4710  * @param   u16             Item to save.
    4711  */
    4712 VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16)
    4713 {
    4714     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4715     return ssmR3DataWrite(pSSM, &u16, sizeof(u16));
    4716 }
    4717 
    4718 
    4719 /**
    4720  * Saves a 16-bit signed integer item to the current data unit.
    4721  *
    4722  * @returns VBox status.
    4723  * @param   pSSM            SSM operation handle.
    4724  * @param   i16             Item to save.
    4725  */
    4726 VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16)
    4727 {
    4728     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4729     return ssmR3DataWrite(pSSM, &i16, sizeof(i16));
    4730 }
    4731 
    4732 
    4733 /**
    4734  * Saves a 32-bit unsigned integer item to the current data unit.
    4735  *
    4736  * @returns VBox status.
    4737  * @param   pSSM            SSM operation handle.
    4738  * @param   u32             Item to save.
    4739  */
    4740 VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32)
    4741 {
    4742     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4743     return ssmR3DataWrite(pSSM, &u32, sizeof(u32));
    4744 }
    4745 
    4746 
    4747 /**
    4748  * Saves a 32-bit signed integer item to the current data unit.
    4749  *
    4750  * @returns VBox status.
    4751  * @param   pSSM            SSM operation handle.
    4752  * @param   i32             Item to save.
    4753  */
    4754 VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32)
    4755 {
    4756     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4757     return ssmR3DataWrite(pSSM, &i32, sizeof(i32));
    4758 }
    4759 
    4760 
    4761 /**
    4762  * Saves a 64-bit unsigned integer item to the current data unit.
    4763  *
    4764  * @returns VBox status.
    4765  * @param   pSSM            SSM operation handle.
    4766  * @param   u64             Item to save.
    4767  */
    4768 VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64)
    4769 {
    4770     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4771     return ssmR3DataWrite(pSSM, &u64, sizeof(u64));
    4772 }
    4773 
    4774 
    4775 /**
    4776  * Saves a 64-bit signed integer item to the current data unit.
    4777  *
    4778  * @returns VBox status.
    4779  * @param   pSSM            SSM operation handle.
    4780  * @param   i64             Item to save.
    4781  */
    4782 VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64)
    4783 {
    4784     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4785     return ssmR3DataWrite(pSSM, &i64, sizeof(i64));
    4786 }
    4787 
    4788 
    4789 /**
    4790  * Saves a 128-bit unsigned integer item to the current data unit.
    4791  *
    4792  * @returns VBox status.
    4793  * @param   pSSM            SSM operation handle.
    4794  * @param   u128            Item to save.
    4795  */
    4796 VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128)
    4797 {
    4798     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4799     return ssmR3DataWrite(pSSM, &u128, sizeof(u128));
    4800 }
    4801 
    4802 
    4803 /**
    4804  * Saves a 128-bit signed integer item to the current data unit.
    4805  *
    4806  * @returns VBox status.
    4807  * @param   pSSM            SSM operation handle.
    4808  * @param   i128            Item to save.
    4809  */
    4810 VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128)
    4811 {
    4812     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4813     return ssmR3DataWrite(pSSM, &i128, sizeof(i128));
    4814 }
    4815 
    4816 
    4817 /**
    4818  * Saves a VBox unsigned integer item to the current data unit.
    4819  *
    4820  * @returns VBox status.
    4821  * @param   pSSM            SSM operation handle.
    4822  * @param   u               Item to save.
    4823  */
    4824 VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u)
    4825 {
    4826     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4827     return ssmR3DataWrite(pSSM, &u, sizeof(u));
    4828 }
    4829 
    4830 
    4831 /**
    4832  * Saves a VBox signed integer item to the current data unit.
    4833  *
    4834  * @returns VBox status.
    4835  * @param   pSSM            SSM operation handle.
    4836  * @param   i               Item to save.
    4837  */
    4838 VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i)
    4839 {
    4840     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4841     return ssmR3DataWrite(pSSM, &i, sizeof(i));
    4842 }
    4843 
    4844 
    4845 /**
    4846  * Saves a GC natural unsigned integer item to the current data unit.
    4847  *
    4848  * @returns VBox status.
    4849  * @param   pSSM            SSM operation handle.
    4850  * @param   u               Item to save.
    4851  *
    4852  * @deprecated Silly type, don't use it.
    4853  */
    4854 VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u)
    4855 {
    4856     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4857     return ssmR3DataWrite(pSSM, &u, sizeof(u));
    4858 }
    4859 
    4860 
    4861 /**
    4862  * Saves a GC unsigned integer register item to the current data unit.
    4863  *
    4864  * @returns VBox status.
    4865  * @param   pSSM            SSM operation handle.
    4866  * @param   u               Item to save.
    4867  */
    4868 VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u)
    4869 {
    4870     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4871     return ssmR3DataWrite(pSSM, &u, sizeof(u));
    4872 }
    4873 
    4874 
    4875 /**
    4876  * Saves a 32 bits GC physical address item to the current data unit.
    4877  *
    4878  * @returns VBox status.
    4879  * @param   pSSM            SSM operation handle.
    4880  * @param   GCPhys          The item to save
    4881  */
    4882 VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)
    4883 {
    4884     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4885     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
    4886 }
    4887 
    4888 
    4889 /**
    4890  * Saves a 64 bits GC physical address item to the current data unit.
    4891  *
    4892  * @returns VBox status.
    4893  * @param   pSSM            SSM operation handle.
    4894  * @param   GCPhys          The item to save
    4895  */
    4896 VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)
    4897 {
    4898     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4899     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
    4900 }
    4901 
    4902 
    4903 /**
    4904  * Saves a GC physical address item to the current data unit.
    4905  *
    4906  * @returns VBox status.
    4907  * @param   pSSM            SSM operation handle.
    4908  * @param   GCPhys          The item to save
    4909  */
    4910 VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys)
    4911 {
    4912     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4913     return ssmR3DataWrite(pSSM, &GCPhys, sizeof(GCPhys));
    4914 }
    4915 
    4916 
    4917 /**
    4918  * Saves a GC virtual address item to the current data unit.
    4919  *
    4920  * @returns VBox status.
    4921  * @param   pSSM            SSM operation handle.
    4922  * @param   GCPtr           The item to save.
    4923  */
    4924 VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr)
    4925 {
    4926     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4927     return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
    4928 }
    4929 
    4930 
    4931 /**
    4932  * Saves an RC virtual address item to the current data unit.
    4933  *
    4934  * @returns VBox status.
    4935  * @param   pSSM            SSM operation handle.
    4936  * @param   RCPtr           The item to save.
    4937  */
    4938 VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr)
    4939 {
    4940     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4941     return ssmR3DataWrite(pSSM, &RCPtr, sizeof(RCPtr));
    4942 }
    4943 
    4944 
    4945 /**
    4946  * Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
    4947  *
    4948  * @returns VBox status.
    4949  * @param   pSSM            SSM operation handle.
    4950  * @param   GCPtr           The item to save.
    4951  */
    4952 VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)
    4953 {
    4954     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4955     return ssmR3DataWrite(pSSM, &GCPtr, sizeof(GCPtr));
    4956 }
    4957 
    4958 
    4959 /**
    4960  * Saves a I/O port address item to the current data unit.
    4961  *
    4962  * @returns VBox status.
    4963  * @param   pSSM            SSM operation handle.
    4964  * @param   IOPort          The item to save.
    4965  */
    4966 VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort)
    4967 {
    4968     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4969     return ssmR3DataWrite(pSSM, &IOPort, sizeof(IOPort));
    4970 }
    4971 
    4972 
    4973 /**
    4974  * Saves a selector item to the current data unit.
    4975  *
    4976  * @returns VBox status.
    4977  * @param   pSSM            SSM operation handle.
    4978  * @param   Sel             The item to save.
    4979  */
    4980 VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel)
    4981 {
    4982     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4983     return ssmR3DataWrite(pSSM, &Sel, sizeof(Sel));
    4984 }
    4985 
    4986 
    4987 /**
    4988  * Saves a memory item to the current data unit.
    4989  *
    4990  * @returns VBox status.
    4991  * @param   pSSM            SSM operation handle.
    4992  * @param   pv              Item to save.
    4993  * @param   cb              Size of the item.
    4994  */
    4995 VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb)
    4996 {
    4997     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    4998     return ssmR3DataWrite(pSSM, pv, cb);
    4999 }
    5000 
    5001 
    5002 /**
    5003  * Saves a zero terminated string item to the current data unit.
    5004  *
    5005  * @returns VBox status.
    5006  * @param   pSSM            SSM operation handle.
    5007  * @param   psz             Item to save.
    5008  */
    5009 VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz)
    5010 {
    5011     AssertMsgReturn(pSSM->enmOp == SSMSTATE_SAVE_EXEC, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
    5012 
    5013     size_t cch = strlen(psz);
    5014     if (cch > _1M)
    5015     {
    5016         AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
    5017         return VERR_TOO_MUCH_DATA;
    5018     }
    5019     uint32_t u32 = (uint32_t)cch;
    5020     int rc = ssmR3DataWrite(pSSM, &u32, sizeof(u32));
    5021     if (rc)
    5022         return rc;
    5023     return ssmR3DataWrite(pSSM, psz, cch);
    5024 }
    5025 
    5026 
    5027 
     3690/* ... Loading and reading starts here ... */
     3691/* ... Loading and reading starts here ... */
     3692/* ... Loading and reading starts here ... */
     3693/* ... Loading and reading starts here ... */
     3694/* ... Loading and reading starts here ... */
     3695/* ... Loading and reading starts here ... */
     3696/* ... Loading and reading starts here ... */
     3697/* ... Loading and reading starts here ... */
     3698/* ... Loading and reading starts here ... */
     3699/* ... Loading and reading starts here ... */
     3700/* ... Loading and reading starts here ... */
     3701/* ... Loading and reading starts here ... */
     3702/* ... Loading and reading starts here ... */
     3703/* ... Loading and reading starts here ... */
     3704/* ... Loading and reading starts here ... */
     3705/* ... Loading and reading starts here ... */
     3706/* ... Loading and reading starts here ... */
    50283707
    50293708
     
    57814460VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool)
    57824461{
    5783     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5784                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4462    SSM_ASSERT_READABLE_RET(pSSM);
    57854463    uint8_t u8; /* see SSMR3PutBool */
    57864464    int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8));
     
    58034481VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8)
    58044482{
    5805     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5806                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4483    SSM_ASSERT_READABLE_RET(pSSM);
    58074484    return ssmR3DataRead(pSSM, pu8, sizeof(*pu8));
    58084485}
     
    58184495VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8)
    58194496{
    5820     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5821                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4497    SSM_ASSERT_READABLE_RET(pSSM);
    58224498    return ssmR3DataRead(pSSM, pi8, sizeof(*pi8));
    58234499}
     
    58334509VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16)
    58344510{
    5835     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5836                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4511    SSM_ASSERT_READABLE_RET(pSSM);
    58374512    return ssmR3DataRead(pSSM, pu16, sizeof(*pu16));
    58384513}
     
    58484523VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16)
    58494524{
    5850     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5851                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4525    SSM_ASSERT_READABLE_RET(pSSM);
    58524526    return ssmR3DataRead(pSSM, pi16, sizeof(*pi16));
    58534527}
     
    58634537VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32)
    58644538{
    5865     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5866                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4539    SSM_ASSERT_READABLE_RET(pSSM);
    58674540    return ssmR3DataRead(pSSM, pu32, sizeof(*pu32));
    58684541}
     
    58784551VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32)
    58794552{
    5880     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5881                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4553    SSM_ASSERT_READABLE_RET(pSSM);
    58824554    return ssmR3DataRead(pSSM, pi32, sizeof(*pi32));
    58834555}
     
    58934565VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64)
    58944566{
    5895     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5896                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4567    SSM_ASSERT_READABLE_RET(pSSM);
    58974568    return ssmR3DataRead(pSSM, pu64, sizeof(*pu64));
    58984569}
     
    59084579VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64)
    59094580{
    5910     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5911                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4581    SSM_ASSERT_READABLE_RET(pSSM);
    59124582    return ssmR3DataRead(pSSM, pi64, sizeof(*pi64));
    59134583}
     
    59234593VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128)
    59244594{
    5925     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5926                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4595    SSM_ASSERT_READABLE_RET(pSSM);
    59274596    return ssmR3DataRead(pSSM, pu128, sizeof(*pu128));
    59284597}
     
    59384607VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128)
    59394608{
    5940     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5941                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4609    SSM_ASSERT_READABLE_RET(pSSM);
    59424610    return ssmR3DataRead(pSSM, pi128, sizeof(*pi128));
    59434611}
     
    59534621VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu)
    59544622{
    5955     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5956                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4623    SSM_ASSERT_READABLE_RET(pSSM);
    59574624    return ssmR3DataRead(pSSM, pu, sizeof(*pu));
    59584625}
     
    59684635VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi)
    59694636{
    5970     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    5971                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4637    SSM_ASSERT_READABLE_RET(pSSM);
    59724638    return ssmR3DataRead(pSSM, pi, sizeof(*pi));
    59734639}
     
    60134679VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)
    60144680{
    6015     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6016                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4681    SSM_ASSERT_READABLE_RET(pSSM);
    60174682    return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
    60184683}
     
    60284693VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)
    60294694{
    6030     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6031                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4695    SSM_ASSERT_READABLE_RET(pSSM);
    60324696    return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys));
    60334697}
     
    60434707VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)
    60444708{
    6045     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6046                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4709    SSM_ASSERT_READABLE_RET(pSSM);
    60474710
    60484711    /*
     
    61214784VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)
    61224785{
    6123     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6124                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4786    SSM_ASSERT_READABLE_RET(pSSM);
    61254787
    61264788    /*
     
    61774839VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)
    61784840{
    6179     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6180                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4841    SSM_ASSERT_READABLE_RET(pSSM);
    61814842    return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr));
    61824843}
     
    61924853VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort)
    61934854{
    6194     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6195                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4855    SSM_ASSERT_READABLE_RET(pSSM);
    61964856    return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort));
    61974857}
     
    62074867VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel)
    62084868{
    6209     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6210                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4869    SSM_ASSERT_READABLE_RET(pSSM);
    62114870    return ssmR3DataRead(pSSM, pSel, sizeof(*pSel));
    62124871}
     
    62234882VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb)
    62244883{
    6225     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6226                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4884    SSM_ASSERT_READABLE_RET(pSSM);
    62274885    return ssmR3DataRead(pSSM, pv, cb);
    62284886}
     
    62544912VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)
    62554913{
    6256     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6257                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4914    SSM_ASSERT_READABLE_RET(pSSM);
    62584915
    62594916    /* read size prefix. */
     
    62854942VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb)
    62864943{
    6287     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6288                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4944    SSM_ASSERT_READABLE_RET(pSSM);
    62894945    while (cb > 0)
    62904946    {
     
    63134969VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM)
    63144970{
    6315     AssertMsgReturn(   pSSM->enmOp == SSMSTATE_LOAD_EXEC
    6316                     || pSSM->enmOp == SSMSTATE_OPEN_READ, ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE);
     4971    SSM_ASSERT_READABLE_RET(pSSM);
    63174972    if (pSSM->u.Read.uFmtVerMajor >= 2)
    63184973    {
     
    63515006
    63525007/**
     5008 * Calculate the checksum of a file portion.
     5009 *
     5010 * @returns VBox status.
     5011 * @param   pStrm       The stream handle
     5012 * @param   off         Where to start checksumming.
     5013 * @param   cb          How much to checksum.
     5014 * @param   pu32CRC     Where to store the calculated checksum.
     5015 */
     5016static int ssmR3CalcChecksum(PSSMSTRM pStrm, uint64_t off, uint64_t cb, uint32_t *pu32CRC)
     5017{
     5018    /*
     5019     * Allocate a buffer.
     5020     */
     5021    const size_t cbBuf = _32K;
     5022    void *pvBuf = RTMemTmpAlloc(cbBuf);
     5023    if (!pvBuf)
     5024        return VERR_NO_TMP_MEMORY;
     5025
     5026    /*
     5027     * Loop reading and calculating CRC32.
     5028     */
     5029    int         rc     = VINF_SUCCESS;
     5030    uint32_t    u32CRC = RTCrc32Start();
     5031    while (cb > 0)
     5032    {
     5033        /* read chunk */
     5034        size_t cbToRead = cbBuf;
     5035        if (cb < cbBuf)
     5036            cbToRead = cb;
     5037        rc = ssmR3StrmPeekAt(pStrm, off, pvBuf, cbToRead, NULL);
     5038        if (RT_FAILURE(rc))
     5039        {
     5040            AssertMsgFailed(("Failed with rc=%Rrc while calculating crc.\n", rc));
     5041            RTMemTmpFree(pvBuf);
     5042            return rc;
     5043        }
     5044
     5045        /* advance */
     5046        cb  -= cbToRead;
     5047        off += cbToRead;
     5048
     5049        /* calc crc32. */
     5050        u32CRC = RTCrc32Process(u32CRC, pvBuf, cbToRead);
     5051    }
     5052    RTMemTmpFree(pvBuf);
     5053
     5054    /* store the calculated crc */
     5055    u32CRC = RTCrc32Finish(u32CRC);
     5056    Log(("SSM: u32CRC=0x%08x\n", u32CRC));
     5057    *pu32CRC = u32CRC;
     5058
     5059    return VINF_SUCCESS;
     5060}
     5061
     5062
     5063/**
     5064 * Validates the header information stored in the handle.
     5065 *
     5066 * @returns VBox status code.
     5067 *
     5068 * @param   pSSM            The handle.
     5069 * @param   fHaveHostBits   Set if the host bits field is valid.
     5070 * @param   fHaveVersion    Set if we have a version.
     5071 */
     5072static int ssmR3ValidateHeaderInfo(PSSMHANDLE pSSM, bool fHaveHostBits, bool fHaveVersion)
     5073{
     5074    Assert(pSSM->u.Read.cbFileHdr < 256 && pSSM->u.Read.cbFileHdr > 32);
     5075    Assert(pSSM->u.Read.uFmtVerMajor == 1 || pSSM->u.Read.uFmtVerMajor == 2);
     5076    Assert(pSSM->u.Read.uFmtVerMinor <= 2);
     5077
     5078    if (fHaveVersion)
     5079    {
     5080        if (    pSSM->u.Read.u16VerMajor == 0
     5081            ||  pSSM->u.Read.u16VerMajor > 1000
     5082            ||  pSSM->u.Read.u16VerMinor > 1000
     5083            ||  pSSM->u.Read.u32VerBuild > _1M
     5084            ||  pSSM->u.Read.u32SvnRev == 0
     5085            ||  pSSM->u.Read.u32SvnRev > 10000000 /*100M*/)
     5086        {
     5087            LogRel(("SSM: Incorrect version values: %u.%u.%u.r%u\n",
     5088                    pSSM->u.Read.u16VerMajor, pSSM->u.Read.u16VerMinor, pSSM->u.Read.u32VerBuild, pSSM->u.Read.u32SvnRev));
     5089            return VERR_SSM_INTEGRITY_VBOX_VERSION;
     5090        }
     5091    }
     5092    else
     5093        AssertLogRelReturn(   pSSM->u.Read.u16VerMajor == 0
     5094                           && pSSM->u.Read.u16VerMinor == 0
     5095                           && pSSM->u.Read.u32VerBuild == 0
     5096                           && pSSM->u.Read.u32SvnRev   == 0,
     5097                           VERR_SSM_INTEGRITY_VBOX_VERSION);
     5098
     5099    if (fHaveHostBits)
     5100    {
     5101        if (    pSSM->u.Read.cHostBits != 32
     5102            &&  pSSM->u.Read.cHostBits != 64)
     5103        {
     5104            LogRel(("SSM: Incorrect cHostBits value: %u\n", pSSM->u.Read.cHostBits));
     5105            return VERR_SSM_INTEGRITY_HEADER;
     5106        }
     5107    }
     5108    else
     5109        AssertLogRelReturn(pSSM->u.Read.cHostBits == 0, VERR_SSM_INTEGRITY_HEADER);
     5110
     5111    if (    pSSM->u.Read.cbGCPhys != sizeof(uint32_t)
     5112        &&  pSSM->u.Read.cbGCPhys != sizeof(uint64_t))
     5113    {
     5114        LogRel(("SSM: Incorrect cbGCPhys value: %d\n", pSSM->u.Read.cbGCPhys));
     5115        return VERR_SSM_INTEGRITY_HEADER;
     5116    }
     5117    if (    pSSM->u.Read.cbGCPtr != sizeof(uint32_t)
     5118        &&  pSSM->u.Read.cbGCPtr != sizeof(uint64_t))
     5119    {
     5120        LogRel(("SSM: Incorrect cbGCPtr value: %d\n", pSSM->u.Read.cbGCPtr));
     5121        return VERR_SSM_INTEGRITY_HEADER;
     5122    }
     5123
     5124    return VINF_SUCCESS;
     5125}
     5126
     5127
     5128/**
     5129 * Reads the header, detects the format version and performs integrity
     5130 * validations.
     5131 *
     5132 * @returns VBox status.
     5133 * @param   File                File to validate.
     5134 *                              The file position is undefined on return.
     5135 * @param   fChecksumIt         Whether to checksum the file or not.  This will
     5136 *                              be ignored if it the stream isn't a file.
     5137 * @param   fChecksumOnRead     Whether to validate the checksum while reading
     5138 *                              the stream instead of up front. If not possible,
     5139 *                              verify the checksum up front.
     5140 * @param   pHdr                Where to store the file header.
     5141 */
     5142static int ssmR3HeaderAndValidate(PSSMHANDLE pSSM, bool fChecksumIt, bool fChecksumOnRead)
     5143{
     5144    /*
     5145     * Read and check the header magic.
     5146     */
     5147    union
     5148    {
     5149        SSMFILEHDR          v2_0;
     5150        SSMFILEHDRV12       v1_2;
     5151        SSMFILEHDRV11       v1_1;
     5152    } uHdr;
     5153    int rc = ssmR3StrmRead(&pSSM->Strm, &uHdr, sizeof(uHdr.v2_0.szMagic));
     5154    if (RT_FAILURE(rc))
     5155    {
     5156        LogRel(("SSM: Failed to read file magic header. rc=%Rrc\n", rc));
     5157        return rc;
     5158    }
     5159    if (memcmp(uHdr.v2_0.szMagic, SSMFILEHDR_MAGIC_BASE, sizeof(SSMFILEHDR_MAGIC_BASE) - 1))
     5160    {
     5161        Log(("SSM: Not a saved state file. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
     5162        return VERR_SSM_INTEGRITY_MAGIC;
     5163    }
     5164
     5165    /*
     5166     * Find the header size and read the rest.
     5167     */
     5168    static const struct
     5169    {
     5170        char        szMagic[sizeof(SSMFILEHDR_MAGIC_V2_0)];
     5171        size_t      cbHdr;
     5172        unsigned    uFmtVerMajor;
     5173        unsigned    uFmtVerMinor;
     5174    }   s_aVers[] =
     5175    {
     5176        { SSMFILEHDR_MAGIC_V2_0, sizeof(SSMFILEHDR),    2, 0 },
     5177        { SSMFILEHDR_MAGIC_V1_2, sizeof(SSMFILEHDRV12), 1, 2 },
     5178        { SSMFILEHDR_MAGIC_V1_1, sizeof(SSMFILEHDRV11), 1, 1 },
     5179    };
     5180    int iVer = RT_ELEMENTS(s_aVers);
     5181    while (iVer-- > 0)
     5182        if (!memcmp(uHdr.v2_0.szMagic, s_aVers[iVer].szMagic, sizeof(uHdr.v2_0.szMagic)))
     5183            break;
     5184    if (iVer < 0)
     5185    {
     5186        Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(uHdr.v2_0.szMagic) - 1, uHdr.v2_0.szMagic));
     5187        return VERR_SSM_INTEGRITY_VERSION;
     5188    }
     5189    pSSM->u.Read.uFmtVerMajor   = s_aVers[iVer].uFmtVerMajor;
     5190    pSSM->u.Read.uFmtVerMinor   = s_aVers[iVer].uFmtVerMinor;
     5191    pSSM->u.Read.cbFileHdr      = s_aVers[iVer].cbHdr;
     5192
     5193    rc = ssmR3StrmRead(&pSSM->Strm, (uint8_t *)&uHdr + sizeof(uHdr.v2_0.szMagic), pSSM->u.Read.cbFileHdr - sizeof(uHdr.v2_0.szMagic));
     5194    if (RT_FAILURE(rc))
     5195    {
     5196        LogRel(("SSM: Failed to read the file header. rc=%Rrc\n", rc));
     5197        return rc;
     5198    }
     5199
     5200    /*
     5201     * Make version specific adjustments.
     5202     */
     5203    if (pSSM->u.Read.uFmtVerMajor >= 2)
     5204    {
     5205        /*
     5206         * Version 2.0 and later.
     5207         */
     5208        bool fChecksummed;
     5209        if (pSSM->u.Read.uFmtVerMinor == 0)
     5210        {
     5211            /* validate the header. */
     5212            SSM_CHECK_CRC32_RET(&uHdr.v2_0, sizeof(uHdr.v2_0), ("Header CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
     5213            if (uHdr.v2_0.u8Reserved)
     5214            {
     5215                LogRel(("SSM: Reserved header field isn't zero: %02x\n", uHdr.v2_0.u8Reserved));
     5216                return VERR_SSM_INTEGRITY;
     5217            }
     5218            if ((uHdr.v2_0.fFlags & ~SSMFILEHDR_FLAGS_STREAM_CRC32))
     5219            {
     5220                LogRel(("SSM: Unknown header flags: %08x\n", uHdr.v2_0.fFlags));
     5221                return VERR_SSM_INTEGRITY;
     5222            }
     5223            if (    uHdr.v2_0.cbMaxDecompr > sizeof(pSSM->u.Read.abDataBuffer)
     5224                ||  uHdr.v2_0.cbMaxDecompr < _1K
     5225                ||  (uHdr.v2_0.cbMaxDecompr & 0xff) != 0)
     5226            {
     5227                LogRel(("SSM: The cbMaxDecompr header field is out of range: %#x\n", uHdr.v2_0.cbMaxDecompr));
     5228                return VERR_SSM_INTEGRITY;
     5229            }
     5230
     5231            /* set the header info. */
     5232            pSSM->u.Read.cHostBits      = uHdr.v2_0.cHostBits;
     5233            pSSM->u.Read.u16VerMajor    = uHdr.v2_0.u16VerMajor;
     5234            pSSM->u.Read.u16VerMinor    = uHdr.v2_0.u16VerMinor;
     5235            pSSM->u.Read.u32VerBuild    = uHdr.v2_0.u32VerBuild;
     5236            pSSM->u.Read.u32SvnRev      = uHdr.v2_0.u32SvnRev;
     5237            pSSM->u.Read.cbGCPhys       = uHdr.v2_0.cbGCPhys;
     5238            pSSM->u.Read.cbGCPtr        = uHdr.v2_0.cbGCPtr;
     5239            pSSM->u.Read.fFixedGCPtrSize = true;
     5240            fChecksummed = !!(uHdr.v2_0.fFlags & SSMFILEHDR_FLAGS_STREAM_CRC32);
     5241        }
     5242        else
     5243            AssertFailedReturn(VERR_INTERNAL_ERROR);
     5244        if (!fChecksummed)
     5245            ssmR3StrmDisableChecksumming(&pSSM->Strm);
     5246
     5247        /*
     5248         * Read and validate the footer if it's a file.
     5249         */
     5250        if (ssmR3StrmIsFile(&pSSM->Strm))
     5251        {
     5252            SSMFILEFTR  Footer;
     5253            uint64_t    offFooter;
     5254            rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(SSMFILEFTR), &Footer, sizeof(Footer), &offFooter);
     5255            AssertLogRelRCReturn(rc, rc);
     5256            if (memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)))
     5257            {
     5258                LogRel(("SSM: Bad footer magic: %.*Rhxs\n", sizeof(Footer.szMagic), &Footer.szMagic[0]));
     5259                return VERR_SSM_INTEGRITY_FOOTER;
     5260            }
     5261            SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Footer CRC mismatch: %08x, correct is %08x\n", u32CRC, u32ActualCRC));
     5262            if (Footer.offStream != offFooter)
     5263            {
     5264                LogRel(("SSM: SSMFILEFTR::offStream is wrong: %llx, expected %llx\n", Footer.offStream, offFooter));
     5265                return VERR_SSM_INTEGRITY_FOOTER;
     5266            }
     5267            if (Footer.u32Reserved)
     5268            {
     5269                LogRel(("SSM: Reserved footer field isn't zero: %08x\n", Footer.u32Reserved));
     5270                return VERR_SSM_INTEGRITY_FOOTER;
     5271            }
     5272            if (    !fChecksummed
     5273                &&  Footer.u32StreamCRC)
     5274            {
     5275                LogRel(("SSM: u32StreamCRC field isn't zero, but header says stream checksumming is disabled.\n"));
     5276                return VERR_SSM_INTEGRITY_FOOTER;
     5277            }
     5278
     5279            pSSM->u.Read.cbLoadFile = offFooter + sizeof(Footer);
     5280            pSSM->u.Read.u32LoadCRC = Footer.u32StreamCRC;
     5281        }
     5282        else
     5283        {
     5284            pSSM->u.Read.cbLoadFile = UINT64_MAX;
     5285            pSSM->u.Read.u32LoadCRC = 0;
     5286        }
     5287
     5288        /*
     5289         * Validate the header info we've set in the handle.
     5290         */
     5291        rc = ssmR3ValidateHeaderInfo(pSSM, true /*fHaveHostBits*/, true /*fHaveVersion*/);
     5292        if (RT_FAILURE(rc))
     5293            return rc;
     5294
     5295        /*
     5296         * Check the checksum if that's called for and possible.
     5297         */
     5298        if (    fChecksummed
     5299            &&  fChecksumIt
     5300            &&  !fChecksumOnRead
     5301            &&  ssmR3StrmIsFile(&pSSM->Strm))
     5302        {
     5303            uint32_t u32CRC;
     5304            rc = ssmR3CalcChecksum(&pSSM->Strm, 0, pSSM->u.Read.cbLoadFile - sizeof(SSMFILEFTR), &u32CRC);
     5305            if (RT_FAILURE(rc))
     5306                return rc;
     5307            if (u32CRC != pSSM->u.Read.u32LoadCRC)
     5308            {
     5309                LogRel(("SSM: Invalid CRC! Calculated %#010x, in footer %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
     5310                return VERR_SSM_INTEGRITY_CRC;
     5311            }
     5312        }
     5313    }
     5314    else
     5315    {
     5316        /*
     5317         * Version 1.x of the format.
     5318         */
     5319        bool        fHaveHostBits = true;
     5320        bool        fHaveVersion  = false;
     5321        RTUUID      MachineUuidFromHdr;
     5322
     5323        ssmR3StrmDisableChecksumming(&pSSM->Strm);
     5324        if (pSSM->u.Read.uFmtVerMinor == 1)
     5325        {
     5326            pSSM->u.Read.cHostBits      = 0; /* unknown */
     5327            pSSM->u.Read.u16VerMajor    = 0;
     5328            pSSM->u.Read.u16VerMinor    = 0;
     5329            pSSM->u.Read.u32VerBuild    = 0;
     5330            pSSM->u.Read.u32SvnRev      = 0;
     5331            pSSM->u.Read.cbLoadFile     = uHdr.v1_1.cbFile;
     5332            pSSM->u.Read.u32LoadCRC     = uHdr.v1_1.u32CRC;
     5333            pSSM->u.Read.cbGCPhys       = sizeof(RTGCPHYS);
     5334            pSSM->u.Read.cbGCPtr        = sizeof(RTGCPTR);
     5335            pSSM->u.Read.fFixedGCPtrSize = false; /* settable */
     5336
     5337            MachineUuidFromHdr  = uHdr.v1_1.MachineUuid;
     5338            fHaveHostBits       = false;
     5339        }
     5340        else if (pSSM->u.Read.uFmtVerMinor == 2)
     5341        {
     5342            pSSM->u.Read.cHostBits      = uHdr.v1_2.cHostBits;
     5343            pSSM->u.Read.u16VerMajor    = uHdr.v1_2.u16VerMajor;
     5344            pSSM->u.Read.u16VerMinor    = uHdr.v1_2.u16VerMinor;
     5345            pSSM->u.Read.u32VerBuild    = uHdr.v1_2.u32VerBuild;
     5346            pSSM->u.Read.u32SvnRev      = uHdr.v1_2.u32SvnRev;
     5347            pSSM->u.Read.cbLoadFile     = uHdr.v1_2.cbFile;
     5348            pSSM->u.Read.u32LoadCRC     = uHdr.v1_2.u32CRC;
     5349            pSSM->u.Read.cbGCPhys       = uHdr.v1_2.cbGCPhys;
     5350            pSSM->u.Read.cbGCPtr        = uHdr.v1_2.cbGCPtr;
     5351            pSSM->u.Read.fFixedGCPtrSize = true;
     5352
     5353            MachineUuidFromHdr  = uHdr.v1_2.MachineUuid;
     5354            fHaveVersion        = true;
     5355        }
     5356        else
     5357            AssertFailedReturn(VERR_INTERNAL_ERROR);
     5358
     5359        /*
     5360         * The MachineUuid must be NULL (was never used).
     5361         */
     5362        if (!RTUuidIsNull(&MachineUuidFromHdr))
     5363        {
     5364            LogRel(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
     5365            return VERR_SMM_INTEGRITY_MACHINE;
     5366        }
     5367
     5368        /*
     5369         * Verify the file size.
     5370         */
     5371        uint64_t cbFile = ssmR3StrmGetSize(&pSSM->Strm);
     5372        if (cbFile != pSSM->u.Read.cbLoadFile)
     5373        {
     5374            LogRel(("SSM: File size mismatch. hdr.cbFile=%lld actual %lld\n", pSSM->u.Read.cbLoadFile, cbFile));
     5375            return VERR_SSM_INTEGRITY_SIZE;
     5376        }
     5377
     5378        /*
     5379         * Validate the header info we've set in the handle.
     5380         */
     5381        rc = ssmR3ValidateHeaderInfo(pSSM, fHaveHostBits, fHaveVersion);
     5382        if (RT_FAILURE(rc))
     5383            return rc;
     5384
     5385        /*
     5386         * Verify the checksum if requested.
     5387         *
     5388         * Note! The checksum is not actually generated for the whole file,
     5389         *       this is of course a bug in the v1.x code that we cannot do
     5390         *       anything about.
     5391         */
     5392        if (    fChecksumIt
     5393            ||  fChecksumOnRead)
     5394        {
     5395            uint32_t u32CRC;
     5396            rc = ssmR3CalcChecksum(&pSSM->Strm,
     5397                                   RT_OFFSETOF(SSMFILEHDRV11, u32CRC) + sizeof(uHdr.v1_1.u32CRC),
     5398                                   cbFile - pSSM->u.Read.cbFileHdr,
     5399                                   &u32CRC);
     5400            if (RT_FAILURE(rc))
     5401                return rc;
     5402            if (u32CRC != pSSM->u.Read.u32LoadCRC)
     5403            {
     5404                LogRel(("SSM: Invalid CRC! Calculated %#010x, in header %#010x\n", u32CRC, pSSM->u.Read.u32LoadCRC));
     5405                return VERR_SSM_INTEGRITY_CRC;
     5406            }
     5407        }
     5408    }
     5409
     5410    return VINF_SUCCESS;
     5411}
     5412
     5413
     5414/**
     5415 * Open a saved state for reading.
     5416 *
     5417 * The file will be positioned at the first data unit upon successful return.
     5418 *
     5419 * @returns VBox status code.
     5420 *
     5421 * @param   pVM                 The VM handle.
     5422 * @param   pszFilename         The filename.
     5423 * @param   fChecksumIt         Check the checksum for the entire file.
     5424 * @param   fChecksumOnRead     Whether to validate the checksum while reading
     5425 *                              the stream instead of up front. If not possible,
     5426 *                              verify the checksum up front.
     5427 * @param   pSSM                Pointer to the handle structure. This will be
     5428 *                              completely initialized on success.
     5429 * @param   cBuffers            The number of stream buffers.
     5430 */
     5431static int ssmR3OpenFile(PVM pVM, const char *pszFilename, bool fChecksumIt, bool fChecksumOnRead,
     5432                         uint32_t cBuffers, PSSMHANDLE pSSM)
     5433{
     5434    /*
     5435     * Initialize the handle.
     5436     */
     5437    pSSM->pVM              = pVM;
     5438    pSSM->enmOp            = SSMSTATE_INVALID;
     5439    pSSM->enmAfter         = SSMAFTER_INVALID;
     5440    pSSM->rc               = VINF_SUCCESS;
     5441    pSSM->cbUnitLeftV1     = 0;
     5442    pSSM->offUnit          = UINT64_MAX;
     5443    pSSM->pfnProgress      = NULL;
     5444    pSSM->pvUser           = NULL;
     5445    pSSM->uPercent         = 0;
     5446    pSSM->offEstProgress   = 0;
     5447    pSSM->cbEstTotal       = 0;
     5448    pSSM->offEst           = 0;
     5449    pSSM->offEstUnitEnd    = 0;
     5450    pSSM->uPercentPrepare  = 5;
     5451    pSSM->uPercentDone     = 2;
     5452
     5453    pSSM->u.Read.pZipDecompV1   = NULL;
     5454    pSSM->u.Read.uFmtVerMajor   = UINT32_MAX;
     5455    pSSM->u.Read.uFmtVerMinor   = UINT32_MAX;
     5456    pSSM->u.Read.cbFileHdr      = UINT32_MAX;
     5457    pSSM->u.Read.cbGCPhys       = UINT8_MAX;
     5458    pSSM->u.Read.cbGCPtr        = UINT8_MAX;
     5459    pSSM->u.Read.fFixedGCPtrSize= false;
     5460    pSSM->u.Read.u16VerMajor    = UINT16_MAX;
     5461    pSSM->u.Read.u16VerMinor    = UINT16_MAX;
     5462    pSSM->u.Read.u32VerBuild    = UINT32_MAX;
     5463    pSSM->u.Read.u32SvnRev      = UINT32_MAX;
     5464    pSSM->u.Read.cHostBits      = UINT8_MAX;
     5465    pSSM->u.Read.cbLoadFile     = UINT64_MAX;
     5466
     5467    pSSM->u.Read.cbRecLeft      = 0;
     5468    pSSM->u.Read.cbDataBuffer   = 0;
     5469    pSSM->u.Read.offDataBuffer  = 0;
     5470    pSSM->u.Read.fEndOfData     = 0;
     5471    pSSM->u.Read.u8TypeAndFlags = 0;
     5472
     5473    /*
     5474     * Try open and validate the file.
     5475     */
     5476    int rc = ssmR3StrmOpenFile(&pSSM->Strm, pszFilename, false /*fWrite*/, fChecksumOnRead, cBuffers);
     5477    if (RT_SUCCESS(rc))
     5478    {
     5479        rc = ssmR3HeaderAndValidate(pSSM, fChecksumIt, fChecksumOnRead);
     5480        if (RT_SUCCESS(rc))
     5481            return rc;
     5482
     5483        /* failure path */
     5484        ssmR3StrmClose(&pSSM->Strm);
     5485    }
     5486    else
     5487        Log(("SSM: Failed to open save state file '%s', rc=%Rrc.\n",  pszFilename, rc));
     5488    return rc;
     5489}
     5490
     5491
     5492/**
     5493 * Find a data unit by name.
     5494 *
     5495 * @returns Pointer to the unit.
     5496 * @returns NULL if not found.
     5497 *
     5498 * @param   pVM             VM handle.
     5499 * @param   pszName         Data unit name.
     5500 * @param   uInstance       The data unit instance id.
     5501 */
     5502static PSSMUNIT ssmR3Find(PVM pVM, const char *pszName, uint32_t uInstance)
     5503{
     5504    size_t   cchName = strlen(pszName);
     5505    PSSMUNIT pUnit = pVM->ssm.s.pHead;
     5506    while (     pUnit
     5507           &&   (   pUnit->u32Instance != uInstance
     5508                 || pUnit->cchName != cchName
     5509                 || memcmp(pUnit->szName, pszName, cchName)))
     5510        pUnit = pUnit->pNext;
     5511    return pUnit;
     5512}
     5513
     5514
     5515/**
     5516 * Executes the loading of a V1.X file.
     5517 *
     5518 * @returns VBox status code.
     5519 * @param   pVM                 The VM handle.
     5520 * @param   pSSM                The saved state handle.
     5521 */
     5522static int ssmR3LoadExecV1(PVM pVM, PSSMHANDLE pSSM)
     5523{
     5524    int     rc;
     5525    char   *pszName = NULL;
     5526    size_t  cchName = 0;
     5527    pSSM->enmOp = SSMSTATE_LOAD_EXEC;
     5528    for (;;)
     5529    {
     5530        /*
     5531         * Save the current file position and read the data unit header.
     5532         */
     5533        uint64_t         offUnit = ssmR3StrmTell(&pSSM->Strm);
     5534        SSMFILEUNITHDRV1 UnitHdr;
     5535        rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName));
     5536        if (RT_SUCCESS(rc))
     5537        {
     5538            /*
     5539             * Check the magic and see if it's valid and whether it is a end header or not.
     5540             */
     5541            if (memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
     5542            {
     5543                if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
     5544                {
     5545                    Log(("SSM: EndOfFile: offset %#9llx size %9d\n", offUnit, UnitHdr.cbUnit));
     5546                    /* Complete the progress bar (pending 99% afterwards). */
     5547                    ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
     5548                    break;
     5549                }
     5550                LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
     5551                        offUnit, offUnit, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]));
     5552                rc = VERR_SSM_INTEGRITY_UNIT_MAGIC;
     5553                break;
     5554            }
     5555
     5556            /*
     5557             * Read the name.
     5558             * Adjust the name buffer first.
     5559             */
     5560            if (cchName < UnitHdr.cchName)
     5561            {
     5562                if (pszName)
     5563                    RTMemTmpFree(pszName);
     5564                cchName = RT_ALIGN_Z(UnitHdr.cchName, 64);
     5565                pszName = (char *)RTMemTmpAlloc(cchName);
     5566            }
     5567            if (pszName)
     5568            {
     5569                rc = ssmR3StrmRead(&pSSM->Strm, pszName, UnitHdr.cchName);
     5570                if (RT_SUCCESS(rc))
     5571                {
     5572                    if (pszName[UnitHdr.cchName - 1])
     5573                    {
     5574                        LogRel(("SSM: Unit name '%.*s' was not properly terminated.\n", UnitHdr.cchName, pszName));
     5575                        rc = VERR_SSM_INTEGRITY_UNIT;
     5576                        break;
     5577                    }
     5578                    Log(("SSM: Data unit: offset %#9llx size %9lld '%s'\n", offUnit, UnitHdr.cbUnit, pszName));
     5579
     5580                    /*
     5581                     * Find the data unit in our internal table.
     5582                     */
     5583                    PSSMUNIT pUnit = ssmR3Find(pVM, pszName, UnitHdr.u32Instance);
     5584                    if (pUnit)
     5585                    {
     5586                        /*
     5587                         * Call the execute handler.
     5588                         */
     5589                        pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[UnitHdr.cchName]);
     5590                        pSSM->offUnit = 0;
     5591                        if (!pUnit->u.Common.pfnLoadExec)
     5592                        {
     5593                            LogRel(("SSM: No load exec callback for unit '%s'!\n", pszName));
     5594                            rc = VERR_SSM_NO_LOAD_EXEC;
     5595                            break;
     5596                        }
     5597                        switch (pUnit->enmType)
     5598                        {
     5599                            case SSMUNITTYPE_DEV:
     5600                                rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
     5601                                break;
     5602                            case SSMUNITTYPE_DRV:
     5603                                rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
     5604                                break;
     5605                            case SSMUNITTYPE_INTERNAL:
     5606                                rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, SSM_PHASE_FINAL);
     5607                                break;
     5608                            case SSMUNITTYPE_EXTERNAL:
     5609                                rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, SSM_PHASE_FINAL);
     5610                                break;
     5611                        }
     5612
     5613                        /*
     5614                         * Close the reader stream.
     5615                         */
     5616                        ssmR3DataReadFinishV1(pSSM);
     5617
     5618                        pUnit->fCalled = true;
     5619                        if (RT_SUCCESS(rc))
     5620                            rc = pSSM->rc;
     5621                        if (RT_SUCCESS(rc))
     5622                        {
     5623                            /*
     5624                             * Now, we'll check the current position to see if all, or
     5625                             * more than all, the data was read.
     5626                             *
     5627                             * Note! Because of buffering / compression we'll only see the
     5628                             * really bad ones here.
     5629                             */
     5630                            uint64_t off = ssmR3StrmTell(&pSSM->Strm);
     5631                            int64_t i64Diff = off - (offUnit + UnitHdr.cbUnit);
     5632                            if (i64Diff < 0)
     5633                            {
     5634                                Log(("SSM: Unit '%s' left %lld bytes unread!\n", pszName, -i64Diff));
     5635                                rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
     5636                                ssmR3Progress(pSSM, offUnit + UnitHdr.cbUnit - pSSM->offEst);
     5637                            }
     5638                            else if (i64Diff > 0)
     5639                            {
     5640                                LogRel(("SSM: Unit '%s' read %lld bytes too much!\n", pszName, i64Diff));
     5641                                rc = VMSetError(pVM, VERR_SSM_LOADED_TOO_MUCH, RT_SRC_POS,
     5642                                                N_("Unit '%s' read %lld bytes too much"), pszName, i64Diff);
     5643                                break;
     5644                            }
     5645
     5646                            pSSM->offUnit = UINT64_MAX;
     5647                        }
     5648                        else
     5649                        {
     5650                            LogRel(("SSM: Load exec failed for '%s' instance #%u ! (version %u)\n",
     5651                                    pszName, UnitHdr.u32Instance, UnitHdr.u32Version));
     5652                            VMSetError(pVM, rc, RT_SRC_POS, N_("Load exec failed for '%s' instance #%u (version %u)"),
     5653                                       pszName, UnitHdr.u32Instance, UnitHdr.u32Version);
     5654                            break;
     5655                        }
     5656                    }
     5657                    else
     5658                    {
     5659                        /*
     5660                         * SSM unit wasn't found - ignore this when loading for the debugger.
     5661                         */
     5662                        LogRel(("SSM: Found no handler for unit '%s'!\n", pszName));
     5663                        rc = VERR_SSM_INTEGRITY_UNIT_NOT_FOUND;
     5664                        if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
     5665                            break;
     5666                        rc = ssmR3StrmSkipTo(&pSSM->Strm, offUnit + UnitHdr.cbUnit);
     5667                    }
     5668                }
     5669            }
     5670            else
     5671                rc = VERR_NO_TMP_MEMORY;
     5672        }
     5673
     5674        /*
     5675         * I/O errors ends up here (yea, I know, very nice programming).
     5676         */
     5677        if (RT_FAILURE(rc))
     5678        {
     5679            LogRel(("SSM: I/O error. rc=%Rrc\n", rc));
     5680            break;
     5681        }
     5682    }
     5683
     5684    RTMemTmpFree(pszName);
     5685    return rc;
     5686}
     5687
     5688
     5689/**
     5690 * Executes the loading of a V2.X file.
     5691 *
     5692 * @returns VBox status code.
     5693 * @param   pVM                 The VM handle.
     5694 * @param   pSSM                The saved state handle.
     5695 */
     5696static int ssmR3LoadExecV2(PVM pVM, PSSMHANDLE pSSM)
     5697{
     5698    pSSM->enmOp = SSMSTATE_LOAD_EXEC;
     5699    for (;;)
     5700    {
     5701        /*
     5702         * Read the unit header and check its integrity.
     5703         */
     5704        uint64_t            offUnit         = ssmR3StrmTell(&pSSM->Strm);
     5705        uint32_t            u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm);
     5706        SSMFILEUNITHDRV2    UnitHdr;
     5707        int rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName));
     5708        if (RT_FAILURE(rc))
     5709            return rc;
     5710        if (RT_UNLIKELY(    memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic))
     5711                        &&  memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END,   sizeof(UnitHdr.szMagic))))
     5712        {
     5713            LogRel(("SSM: Unit at %#llx (%lld): Invalid unit magic: %.*Rhxs!\n",
     5714                    offUnit, offUnit, sizeof(UnitHdr.szMagic) - 1, &UnitHdr.szMagic[0]));
     5715            return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_MAGIC, RT_SRC_POS,
     5716                              N_("Unit at %#llx (%lld): Invalid unit magic"), offUnit, offUnit);
     5717        }
     5718        if (UnitHdr.cbName)
     5719        {
     5720            AssertLogRelMsgReturn(UnitHdr.cbName <= sizeof(UnitHdr.szName),
     5721                                  ("Unit at %#llx (%lld): UnitHdr.cbName=%u > %u\n",
     5722                                   offUnit, offUnit, UnitHdr.cbName, sizeof(UnitHdr.szName)),
     5723                                  VERR_SSM_INTEGRITY_UNIT);
     5724            rc = ssmR3StrmRead(&pSSM->Strm, &UnitHdr.szName[0], UnitHdr.cbName);
     5725            if (RT_FAILURE(rc))
     5726                return rc;
     5727            AssertLogRelMsgReturn(!UnitHdr.szName[UnitHdr.cbName - 1],
     5728                                  ("Unit at %#llx (%lld): Name %.*Rhxs was not properly terminated.\n",
     5729                                   offUnit, offUnit, UnitHdr.cbName, UnitHdr.szName),
     5730                                  VERR_SSM_INTEGRITY_UNIT);
     5731        }
     5732        SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
     5733                            ("Unit at %#llx (%lld): CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, u32CRC, u32ActualCRC));
     5734        AssertLogRelMsgReturn(UnitHdr.offStream == offUnit,
     5735                              ("Unit at %#llx (%lld): offStream=%#llx, expected %#llx\n", offUnit, offUnit, UnitHdr.offStream, offUnit),
     5736                              VERR_SSM_INTEGRITY_UNIT);
     5737        AssertLogRelMsgReturn(UnitHdr.u32CurStreamCRC == u32CurStreamCRC || !pSSM->Strm.fChecksummed,
     5738                              ("Unit at %#llx (%lld): Stream CRC mismatch: %08x, correct is %08x\n", offUnit, offUnit, UnitHdr.u32CurStreamCRC, u32CurStreamCRC),
     5739                              VERR_SSM_INTEGRITY_UNIT);
     5740        AssertLogRelMsgReturn(!UnitHdr.fFlags, ("Unit at %#llx (%lld): fFlags=%08x\n", offUnit, offUnit, UnitHdr.fFlags),
     5741                              VERR_SSM_INTEGRITY_UNIT);
     5742        if (!memcmp(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END,   sizeof(UnitHdr.szMagic)))
     5743        {
     5744            AssertLogRelMsgReturn(   UnitHdr.cbName       == 0
     5745                                  && UnitHdr.u32Instance  == 0
     5746                                  && UnitHdr.u32Version   == 0
     5747                                  && UnitHdr.u32Phase     == SSM_PHASE_FINAL,
     5748                                  ("Unit at %#llx (%lld): Malformed END unit\n", offUnit, offUnit),
     5749                                  VERR_SSM_INTEGRITY_UNIT);
     5750
     5751            /*
     5752             * Complete the progress bar (pending 99% afterwards) and RETURN.
     5753             */
     5754            Log(("SSM: Unit at %#9llx: END UNIT\n", offUnit));
     5755            ssmR3Progress(pSSM, pSSM->cbEstTotal - pSSM->offEst);
     5756            return VINF_SUCCESS;
     5757        }
     5758        AssertLogRelMsgReturn(UnitHdr.cbName > 1, ("Unit at %#llx (%lld): No name\n", offUnit, offUnit), VERR_SSM_INTEGRITY);
     5759
     5760        Log(("SSM: Unit at %#9llx: '%s', instance %u, phase %#x, version %u\n",
     5761             offUnit, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Phase, UnitHdr.u32Version));
     5762
     5763        /*
     5764         * Find the data unit in our internal table.
     5765         */
     5766        PSSMUNIT pUnit = ssmR3Find(pVM, UnitHdr.szName, UnitHdr.u32Instance);
     5767        if (pUnit)
     5768        {
     5769            /*
     5770             * Call the execute handler.
     5771             */
     5772            AssertLogRelMsgReturn(pUnit->u.Common.pfnLoadExec,
     5773                                  ("SSM: No load exec callback for unit '%s'!\n", UnitHdr.szName),
     5774                                  VERR_SSM_NO_LOAD_EXEC);
     5775            ssmR3DataReadBeginV2(pSSM);
     5776            switch (pUnit->enmType)
     5777            {
     5778                case SSMUNITTYPE_DEV:
     5779                    rc = pUnit->u.Dev.pfnLoadExec(pUnit->u.Dev.pDevIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
     5780                    break;
     5781                case SSMUNITTYPE_DRV:
     5782                    rc = pUnit->u.Drv.pfnLoadExec(pUnit->u.Drv.pDrvIns, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
     5783                    break;
     5784                case SSMUNITTYPE_INTERNAL:
     5785                    rc = pUnit->u.Internal.pfnLoadExec(pVM, pSSM, UnitHdr.u32Version, UnitHdr.u32Phase);
     5786                    break;
     5787                case SSMUNITTYPE_EXTERNAL:
     5788                    rc = pUnit->u.External.pfnLoadExec(pSSM, pUnit->u.External.pvUser, UnitHdr.u32Version, UnitHdr.u32Phase);
     5789                    break;
     5790            }
     5791            ssmR3DataReadFinishV2(pSSM);
     5792            pUnit->fCalled = true;
     5793            if (RT_SUCCESS(rc))
     5794                rc = pSSM->rc;
     5795            if (RT_SUCCESS(rc))
     5796                pSSM->offUnit = UINT64_MAX;
     5797            else
     5798            {
     5799                LogRel(("SSM: LoadExec failed for '%s' instance #%u (version %u, phase %#x): %Rrc\n",
     5800                        UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Version, UnitHdr.u32Phase, rc));
     5801                return VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to load unit '%s'"), UnitHdr.szName);
     5802            }
     5803        }
     5804        else
     5805        {
     5806            /*
     5807             * SSM unit wasn't found - ignore this when loading for the debugger.
     5808             */
     5809            LogRel(("SSM: Found no handler for unit '%s' instance #%u!\n", UnitHdr.szName, UnitHdr.u32Instance));
     5810            if (pSSM->enmAfter != SSMAFTER_DEBUG_IT)
     5811                return VMSetError(pVM, VERR_SSM_INTEGRITY_UNIT_NOT_FOUND, RT_SRC_POS,
     5812                                  N_("Found no handler for unit '%s' instance #%u"), UnitHdr.szName, UnitHdr.u32Instance);
     5813            SSMR3SkipToEndOfUnit(pSSM);
     5814            ssmR3DataReadFinishV2(pSSM);
     5815        }
     5816    }
     5817    /* won't get here */
     5818}
     5819
     5820
     5821
     5822
     5823/**
     5824 * Load VM save operation.
     5825 *
     5826 * @returns VBox status.
     5827 *
     5828 * @param   pVM             The VM handle.
     5829 * @param   pszFilename     Name of the file to save the state in.
     5830 * @param   enmAfter        What is planned after a successful load operation.
     5831 *                          Only acceptable values are SSMAFTER_RESUME and SSMAFTER_DEBUG_IT.
     5832 * @param   pfnProgress     Progress callback. Optional.
     5833 * @param   pvUser          User argument for the progress callback.
     5834 *
     5835 * @thread  EMT
     5836 */
     5837VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
     5838{
     5839    LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
     5840    VM_ASSERT_EMT(pVM);
     5841
     5842    /*
     5843     * Validate input.
     5844     */
     5845    if (    enmAfter != SSMAFTER_RESUME
     5846        &&  enmAfter != SSMAFTER_DEBUG_IT)
     5847    {
     5848        AssertMsgFailed(("Invalid enmAfter=%d!\n", enmAfter));
     5849        return VERR_INVALID_PARAMETER;
     5850    }
     5851
     5852    /*
     5853     * Create the handle and open the file.
     5854     */
     5855    SSMHANDLE Handle;
     5856    int rc = ssmR3OpenFile(pVM, pszFilename, false /* fChecksumIt */, true /* fChecksumOnRead */, 8 /*cBuffers*/, &Handle);
     5857    if (RT_SUCCESS(rc))
     5858    {
     5859        ssmR3StrmStartIoThread(&Handle.Strm);
     5860
     5861        Handle.enmAfter     = enmAfter;
     5862        Handle.pfnProgress  = pfnProgress;
     5863        Handle.pvUser       = pvUser;
     5864
     5865        if (Handle.u.Read.u16VerMajor)
     5866            LogRel(("SSM: File header: Format %u.%u, VirtualBox Version %u.%u.%u r%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n",
     5867                    Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
     5868                    Handle.u.Read.u16VerMajor, Handle.u.Read.u16VerMinor, Handle.u.Read.u32VerBuild, Handle.u.Read.u32SvnRev,
     5869                    Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
     5870        else
     5871            LogRel(("SSM: File header: Format %u.%u, %u-bit host, cbGCPhys=%u, cbGCPtr=%u\n" ,
     5872                    Handle.u.Read.uFmtVerMajor, Handle.u.Read.uFmtVerMinor,
     5873                    Handle.u.Read.cHostBits, Handle.u.Read.cbGCPhys, Handle.u.Read.cbGCPtr));
     5874
     5875        if (pfnProgress)
     5876            pfnProgress(pVM, Handle.uPercent, pvUser);
     5877
     5878        /*
     5879         * Clear the per unit flags.
     5880         */
     5881        PSSMUNIT pUnit;
     5882        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
     5883            pUnit->fCalled = false;
     5884
     5885        /*
     5886         * Do the prepare run.
     5887         */
     5888        Handle.rc = VINF_SUCCESS;
     5889        Handle.enmOp = SSMSTATE_LOAD_PREP;
     5890        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
     5891        {
     5892            if (pUnit->u.Common.pfnLoadPrep)
     5893            {
     5894                pUnit->fCalled = true;
     5895                switch (pUnit->enmType)
     5896                {
     5897                    case SSMUNITTYPE_DEV:
     5898                        rc = pUnit->u.Dev.pfnLoadPrep(pUnit->u.Dev.pDevIns, &Handle);
     5899                        break;
     5900                    case SSMUNITTYPE_DRV:
     5901                        rc = pUnit->u.Drv.pfnLoadPrep(pUnit->u.Drv.pDrvIns, &Handle);
     5902                        break;
     5903                    case SSMUNITTYPE_INTERNAL:
     5904                        rc = pUnit->u.Internal.pfnLoadPrep(pVM, &Handle);
     5905                        break;
     5906                    case SSMUNITTYPE_EXTERNAL:
     5907                        rc = pUnit->u.External.pfnLoadPrep(&Handle, pUnit->u.External.pvUser);
     5908                        break;
     5909                }
     5910                if (RT_FAILURE(rc))
     5911                {
     5912                    LogRel(("SSM: Prepare load failed with rc=%Rrc for data unit '%s.\n", rc, pUnit->szName));
     5913                    break;
     5914                }
     5915            }
     5916        }
     5917
     5918        /* pending 2% */
     5919        if (pfnProgress)
     5920            pfnProgress(pVM, Handle.uPercentPrepare-1, pvUser);
     5921        Handle.uPercent      = Handle.uPercentPrepare;
     5922        Handle.cbEstTotal    = Handle.u.Read.cbLoadFile;
     5923        Handle.offEstUnitEnd = Handle.u.Read.cbLoadFile;
     5924
     5925        /*
     5926         * Do the execute run.
     5927         */
     5928        if (RT_SUCCESS(rc))
     5929        {
     5930            if (Handle.u.Read.uFmtVerMajor >= 2)
     5931                rc = ssmR3LoadExecV2(pVM, &Handle);
     5932            else
     5933                rc = ssmR3LoadExecV1(pVM, &Handle);
     5934            /* (progress should be pending 99% now) */
     5935            AssertMsg(RT_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
     5936        }
     5937
     5938        /*
     5939         * Do the done run.
     5940         */
     5941        Handle.rc = rc;
     5942        Handle.enmOp = SSMSTATE_LOAD_DONE;
     5943        for (pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext)
     5944        {
     5945            if (    pUnit->u.Common.pfnLoadDone
     5946                && (   pUnit->fCalled
     5947                    || (!pUnit->u.Common.pfnLoadPrep && !pUnit->u.Common.pfnLoadExec)))
     5948            {
     5949                rc = VINF_SUCCESS;
     5950                switch (pUnit->enmType)
     5951                {
     5952                    case SSMUNITTYPE_DEV:
     5953                        rc = pUnit->u.Dev.pfnLoadDone(pUnit->u.Dev.pDevIns, &Handle);
     5954                        break;
     5955                    case SSMUNITTYPE_DRV:
     5956                        rc = pUnit->u.Drv.pfnLoadDone(pUnit->u.Drv.pDrvIns, &Handle);
     5957                        break;
     5958                    case SSMUNITTYPE_INTERNAL:
     5959                        rc = pUnit->u.Internal.pfnLoadDone(pVM, &Handle);
     5960                        break;
     5961                    case SSMUNITTYPE_EXTERNAL:
     5962                        rc = pUnit->u.External.pfnLoadDone(&Handle, pUnit->u.External.pvUser);
     5963                        break;
     5964                }
     5965                if (RT_FAILURE(rc))
     5966                {
     5967                    LogRel(("SSM: LoadDone failed with rc=%Rrc for data unit '%s' instance #%u.\n",
     5968                            rc, pUnit->szName, pUnit->u32Instance));
     5969                    if (RT_SUCCESS(Handle.rc))
     5970                        Handle.rc = rc;
     5971                }
     5972            }
     5973        }
     5974        rc = Handle.rc;
     5975
     5976        /* progress */
     5977        if (pfnProgress)
     5978            pfnProgress(pVM, 99, pvUser);
     5979
     5980        ssmR3StrmClose(&Handle.Strm);
     5981    }
     5982
     5983    /*
     5984     * Done
     5985     */
     5986    if (RT_SUCCESS(rc))
     5987    {
     5988        /* progress */
     5989        if (pfnProgress)
     5990            pfnProgress(pVM, 100, pvUser);
     5991        Log(("SSM: Load of '%s' completed!\n", pszFilename));
     5992    }
     5993    return rc;
     5994}
     5995
     5996
     5997/**
     5998 * Validates a file as a validate SSM saved state.
     5999 *
     6000 * This will only verify the file format, the format and content of individual
     6001 * data units are not inspected.
     6002 *
     6003 * @returns VINF_SUCCESS if valid.
     6004 * @returns VBox status code on other failures.
     6005 *
     6006 * @param   pszFilename     The path to the file to validate.
     6007 * @param   fChecksumIt     Whether to checksum the file or not.
     6008 *
     6009 * @thread  Any.
     6010 */
     6011VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, bool fChecksumIt)
     6012{
     6013    LogFlow(("SSMR3ValidateFile: pszFilename=%p:{%s} fChecksumIt=%RTbool\n", pszFilename, pszFilename, fChecksumIt));
     6014
     6015    /*
     6016     * Try open the file and validate it.
     6017     */
     6018    SSMHANDLE Handle;
     6019    int rc = ssmR3OpenFile(NULL, pszFilename, fChecksumIt, false /*fChecksumOnRead*/, 1 /*cBuffers*/, &Handle);
     6020    if (RT_SUCCESS(rc))
     6021        ssmR3StrmClose(&Handle.Strm);
     6022    else
     6023        Log(("SSM: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
     6024    return rc;
     6025}
     6026
     6027
     6028/**
     6029 * Opens a saved state file for reading.
     6030 *
     6031 * @returns VBox status code.
     6032 *
     6033 * @param   pszFilename     The path to the saved state file.
     6034 * @param   fFlags          Open flags. Reserved, must be 0.
     6035 * @param   ppSSM           Where to store the SSM handle.
     6036 *
     6037 * @thread  Any.
     6038 */
     6039VMMR3DECL(int) SSMR3Open(const char *pszFilename, unsigned fFlags, PSSMHANDLE *ppSSM)
     6040{
     6041    LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
     6042
     6043    /*
     6044     * Validate input.
     6045     */
     6046    AssertMsgReturn(VALID_PTR(pszFilename), ("%p\n", pszFilename), VERR_INVALID_PARAMETER);
     6047    AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
     6048    AssertMsgReturn(VALID_PTR(ppSSM), ("%p\n", ppSSM), VERR_INVALID_PARAMETER);
     6049
     6050    /*
     6051     * Allocate a handle.
     6052     */
     6053    PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM));
     6054    AssertReturn(pSSM, VERR_NO_MEMORY);
     6055
     6056    /*
     6057     * Try open the file and validate it.
     6058     */
     6059    int rc = ssmR3OpenFile(NULL, pszFilename, false /*fChecksumIt*/, true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM);
     6060    if (RT_SUCCESS(rc))
     6061    {
     6062        pSSM->enmAfter = SSMAFTER_OPENED;
     6063        pSSM->enmOp    = SSMSTATE_OPEN_READ;
     6064        *ppSSM = pSSM;
     6065        LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM));
     6066        return VINF_SUCCESS;
     6067    }
     6068
     6069    Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n",  pszFilename, rc));
     6070    RTMemFree(pSSM);
     6071    return rc;
     6072
     6073}
     6074
     6075
     6076/**
     6077 * Closes a saved state file opened by SSMR3Open().
     6078 *
     6079 * @returns VBox status code.
     6080 *
     6081 * @param   pSSM            The SSM handle returned by SSMR3Open().
     6082 *
     6083 * @thread  Any, but the caller is responsible for serializing calls per handle.
     6084 */
     6085VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM)
     6086{
     6087    LogFlow(("SSMR3Close: pSSM=%p\n", pSSM));
     6088
     6089    /*
     6090     * Validate input.
     6091     */
     6092    AssertMsgReturn(VALID_PTR(pSSM), ("%p\n", pSSM), VERR_INVALID_PARAMETER);
     6093    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     6094    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     6095
     6096    /*
     6097     * Close the stream and free the handle.
     6098     */
     6099    int rc = ssmR3StrmClose(&pSSM->Strm);
     6100    if (pSSM->u.Read.pZipDecompV1)
     6101    {
     6102        RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
     6103        pSSM->u.Read.pZipDecompV1 = NULL;
     6104    }
     6105    RTMemFree(pSSM);
     6106    return rc;
     6107}
     6108
     6109
     6110/**
     6111 * Worker for SSMR3Seek that seeks version 1 saved state files.
     6112 *
     6113 * @returns VBox status code.
     6114 * @param   pSSM                The SSM handle.
     6115 * @param   pszUnit             The unit to seek to.
     6116 * @param   iInstance           The particulart insance we seek.
     6117 * @param   piVersion           Where to store the unit version number.
     6118 */
     6119static int ssmR3FileSeekV1(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
     6120{
     6121    /*
     6122     * Walk the data units until we find EOF or a match.
     6123     */
     6124    size_t              cbUnitNm = strlen(pszUnit) + 1;
     6125    AssertLogRelReturn(cbUnitNm <= SSM_MAX_NAME_SIZE, VERR_SSM_UNIT_NOT_FOUND);
     6126    char                szName[SSM_MAX_NAME_SIZE];
     6127    SSMFILEUNITHDRV1    UnitHdr;
     6128    for (RTFOFF off = pSSM->u.Read.cbFileHdr; ; off += UnitHdr.cbUnit)
     6129    {
     6130        /*
     6131         * Read the unit header and verify it.
     6132         */
     6133        int rc = ssmR3StrmPeekAt(&pSSM->Strm, off, &UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV1, szName), NULL);
     6134        AssertRCReturn(rc, rc);
     6135        if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(SSMFILEUNITHDR_MAGIC)))
     6136        {
     6137            /*
     6138             * Does what we've got match, if so read the name.
     6139             */
     6140            if (    UnitHdr.u32Instance == iInstance
     6141                &&  UnitHdr.cchName     == cbUnitNm)
     6142            {
     6143                rc = ssmR3StrmPeekAt(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName), szName, cbUnitNm, NULL);
     6144                AssertRCReturn(rc, rc);
     6145                AssertLogRelMsgReturn(!szName[UnitHdr.cchName - 1],
     6146                                      (" Unit name '%.*s' was not properly terminated.\n", cbUnitNm, szName),
     6147                                      VERR_SSM_INTEGRITY_UNIT);
     6148
     6149                /*
     6150                 * Does the name match?
     6151                 */
     6152                if (!memcmp(szName, pszUnit, cbUnitNm))
     6153                {
     6154                    rc = ssmR3StrmSeek(&pSSM->Strm, off + RT_OFFSETOF(SSMFILEUNITHDRV1, szName) + cbUnitNm, RTFILE_SEEK_BEGIN, 0);
     6155                    pSSM->cbUnitLeftV1 = UnitHdr.cbUnit - RT_OFFSETOF(SSMFILEUNITHDRV1, szName[cbUnitNm]);
     6156                    pSSM->offUnit = 0;
     6157                    if (piVersion)
     6158                        *piVersion = UnitHdr.u32Version;
     6159                    return VINF_SUCCESS;
     6160                }
     6161            }
     6162        }
     6163        else if (!memcmp(&UnitHdr.achMagic[0], SSMFILEUNITHDR_END, sizeof(SSMFILEUNITHDR_END)))
     6164            return VERR_SSM_UNIT_NOT_FOUND;
     6165        else
     6166            AssertLogRelMsgFailedReturn(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
     6167                                         off, sizeof(UnitHdr.achMagic) - 1, &UnitHdr.achMagic[0]),
     6168                                        VERR_SSM_INTEGRITY_UNIT_MAGIC);
     6169    }
     6170    /* won't get here. */
     6171}
     6172
     6173
     6174/**
     6175 * Worker for ssmR3FileSeekV2 for simplifying memory cleanup.
     6176 *
     6177 * @returns VBox status code.
     6178 * @param   pSSM                The SSM handle.
     6179 * @param   pDir                The directory buffer.
     6180 * @param   cbDir               The size of the directory.
     6181 * @param   cDirEntries         The number of directory entries.
     6182 * @param   offDir              The directory offset in the file.
     6183 * @param   pszUnit             The unit to seek to.
     6184 * @param   iInstance           The particulart insance we seek.
     6185 * @param   piVersion           Where to store the unit version number.
     6186 */
     6187static int ssmR3FileSeekSubV2(PSSMHANDLE pSSM, PSSMFILEDIR pDir, size_t cbDir, uint32_t cDirEntries, uint64_t offDir,
     6188                              const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
     6189{
     6190    /*
     6191     * Read it.
     6192     */
     6193    int rc = ssmR3StrmPeekAt(&pSSM->Strm, offDir, pDir, cbDir, NULL);
     6194    AssertLogRelRCReturn(rc, rc);
     6195    AssertLogRelReturn(!memcmp(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)), VERR_SSM_INTEGRITY_DIR_MAGIC);
     6196    SSM_CHECK_CRC32_RET(pDir, cbDir, ("Bad directory CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
     6197    AssertLogRelMsgReturn(pDir->cEntries == cDirEntries,
     6198                          ("Bad directory entry count: %#x, expected %#x (from the footer)\n", pDir->cEntries, cDirEntries),
     6199                           VERR_SSM_INTEGRITY_DIR);
     6200    for (uint32_t i = 0; i < cDirEntries; i++)
     6201        AssertLogRelMsgReturn(pDir->aEntries[i].off < offDir,
     6202                              ("i=%u off=%lld offDir=%lld\n", i, pDir->aEntries[i].off, offDir),
     6203                              VERR_SSM_INTEGRITY_DIR);
     6204
     6205    /*
     6206     * Search the directory.
     6207     */
     6208    size_t          cbUnitNm   = strlen(pszUnit) + 1;
     6209    uint32_t const  u32NameCRC = RTCrc32(pszUnit, cbUnitNm - 1);
     6210    for (uint32_t i = 0; i < cDirEntries; i++)
     6211    {
     6212        if (    pDir->aEntries[i].u32NameCRC  == u32NameCRC
     6213            &&  pDir->aEntries[i].u32Instance == iInstance)
     6214        {
     6215            /*
     6216             * Read and validate the unit header.
     6217             */
     6218            SSMFILEUNITHDRV2    UnitHdr;
     6219            size_t              cbToRead = sizeof(UnitHdr);
     6220            if (pDir->aEntries[i].off + cbToRead > offDir)
     6221            {
     6222                cbToRead = offDir - pDir->aEntries[i].off;
     6223                RT_ZERO(UnitHdr);
     6224            }
     6225            rc = ssmR3StrmPeekAt(&pSSM->Strm, pDir->aEntries[i].off, &UnitHdr, cbToRead, NULL);
     6226            AssertLogRelRCReturn(rc, rc);
     6227
     6228            AssertLogRelMsgReturn(!memcmp(UnitHdr.szMagic, SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)),
     6229                                  ("Bad unit header or dictionary offset: i=%u off=%lld\n", i, pDir->aEntries[i].off),
     6230                                  VERR_SSM_INTEGRITY_UNIT);
     6231            AssertLogRelMsgReturn(UnitHdr.offStream == pDir->aEntries[i].off,
     6232                                  ("Bad unit header: i=%d off=%lld offStream=%lld\n", i, pDir->aEntries[i].off, UnitHdr.offStream),
     6233                                  VERR_SSM_INTEGRITY_UNIT);
     6234            AssertLogRelMsgReturn(UnitHdr.u32Instance == pDir->aEntries[i].u32Instance,
     6235                                  ("Bad unit header: i=%d off=%lld u32Instance=%u Dir.u32Instance=%u\n",
     6236                                   i, pDir->aEntries[i].off, UnitHdr.u32Instance, pDir->aEntries[i].u32Instance),
     6237                                  VERR_SSM_INTEGRITY_UNIT);
     6238            uint32_t cbUnitHdr = RT_UOFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]);
     6239            AssertLogRelMsgReturn(   UnitHdr.cbName > 0
     6240                                  && UnitHdr.cbName < sizeof(UnitHdr)
     6241                                  && cbUnitHdr <= cbToRead,
     6242                                  ("Bad unit header: i=%u off=%lld cbName=%#x cbToRead=%#x\n", i, pDir->aEntries[i].off, UnitHdr.cbName, cbToRead),
     6243                                  VERR_SSM_INTEGRITY_UNIT);
     6244            SSM_CHECK_CRC32_RET(&UnitHdr, RT_OFFSETOF(SSMFILEUNITHDRV2, szName[UnitHdr.cbName]),
     6245                                ("Bad unit header CRC: i=%u off=%lld u32CRC=%#x u32ActualCRC=%#x\n",
     6246                                 i, pDir->aEntries[i].off, u32CRC, u32ActualCRC));
     6247
     6248            /*
     6249             * Ok, it is valid, get on with the comparing now.
     6250             */
     6251            if (    UnitHdr.cbName == cbUnitNm
     6252                &&  !memcmp(UnitHdr.szName, pszUnit, cbUnitNm))
     6253            {
     6254                if (piVersion)
     6255                    *piVersion = UnitHdr.u32Version;
     6256                rc = ssmR3StrmSeek(&pSSM->Strm, pDir->aEntries[i].off + cbUnitHdr, RTFILE_SEEK_BEGIN,
     6257                                   RTCrc32Process(UnitHdr.u32CurStreamCRC, &UnitHdr, cbUnitHdr));
     6258                AssertLogRelRCReturn(rc, rc);
     6259                ssmR3DataReadBeginV2(pSSM);
     6260                return VINF_SUCCESS;
     6261            }
     6262        }
     6263    }
     6264
     6265    return VERR_SSM_UNIT_NOT_FOUND;
     6266}
     6267
     6268
     6269/**
     6270 * Worker for SSMR3Seek that seeks version 2 saved state files.
     6271 *
     6272 * @returns VBox status code.
     6273 * @param   pSSM                The SSM handle.
     6274 * @param   pszUnit             The unit to seek to.
     6275 * @param   iInstance           The particulart insance we seek.
     6276 * @param   piVersion           Where to store the unit version number.
     6277 */
     6278static int ssmR3FileSeekV2(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
     6279{
     6280    /*
     6281     * Read the footer, allocate a temporary buffer for the dictionary and
     6282     * pass it down to a worker to simplify cleanup.
     6283     */
     6284    uint64_t        offFooter;
     6285    SSMFILEFTR      Footer;
     6286    int rc = ssmR3StrmPeekAt(&pSSM->Strm, -(RTFOFF)sizeof(Footer), &Footer, sizeof(Footer), &offFooter);
     6287    AssertLogRelRCReturn(rc, rc);
     6288    AssertLogRelReturn(!memcmp(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)), VERR_SSM_INTEGRITY);
     6289    SSM_CHECK_CRC32_RET(&Footer, sizeof(Footer), ("Bad footer CRC: %08x, actual %08x\n", u32CRC, u32ActualCRC));
     6290
     6291    size_t const    cbDir = RT_OFFSETOF(SSMFILEDIR, aEntries[Footer.cDirEntries]);
     6292    PSSMFILEDIR     pDir  = (PSSMFILEDIR)RTMemTmpAlloc(cbDir);
     6293    if (RT_UNLIKELY(!pDir))
     6294        return VERR_NO_TMP_MEMORY;
     6295    rc = ssmR3FileSeekSubV2(pSSM, pDir, cbDir, Footer.cDirEntries, offFooter - cbDir,
     6296                            pszUnit, iInstance, piVersion);
     6297    RTMemTmpFree(pDir);
     6298
     6299    return rc;
     6300}
     6301
     6302
     6303/**
     6304 * Seeks to a specific data unit.
     6305 *
     6306 * After seeking it's possible to use the getters to on
     6307 * that data unit.
     6308 *
     6309 * @returns VBox status code.
     6310 * @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
     6311 *
     6312 * @param   pSSM            The SSM handle returned by SSMR3Open().
     6313 * @param   pszUnit         The name of the data unit.
     6314 * @param   iInstance       The instance number.
     6315 * @param   piVersion       Where to store the version number. (Optional)
     6316 *
     6317 * @thread  Any, but the caller is responsible for serializing calls per handle.
     6318 */
     6319VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
     6320{
     6321    LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
     6322             pSSM, pszUnit, pszUnit, iInstance, piVersion));
     6323
     6324    /*
     6325     * Validate input.
     6326     */
     6327    AssertPtrReturn(pSSM, VERR_INVALID_PARAMETER);
     6328    AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
     6329    AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER);
     6330    AssertPtrReturn(pszUnit, VERR_INVALID_POINTER);
     6331    AssertMsgReturn(!piVersion || VALID_PTR(piVersion), ("%p\n", piVersion), VERR_INVALID_POINTER);
     6332
     6333    /*
     6334     * Reset the state.
     6335     */
     6336    if (pSSM->u.Read.pZipDecompV1)
     6337    {
     6338        RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1);
     6339        pSSM->u.Read.pZipDecompV1 = NULL;
     6340    }
     6341    pSSM->cbUnitLeftV1  = 0;
     6342    pSSM->offUnit       = UINT64_MAX;
     6343
     6344    /*
     6345     * Call the version specific workers.
     6346     */
     6347    if (pSSM->u.Read.uFmtVerMajor >= 2)
     6348        pSSM->rc = ssmR3FileSeekV2(pSSM, pszUnit, iInstance, piVersion);
     6349    else
     6350        pSSM->rc = ssmR3FileSeekV1(pSSM, pszUnit, iInstance, piVersion);
     6351    return pSSM->rc;
     6352}
     6353
     6354
     6355
     6356/* ... Misc APIs ... */
     6357/* ... Misc APIs ... */
     6358/* ... Misc APIs ... */
     6359/* ... Misc APIs ... */
     6360/* ... Misc APIs ... */
     6361/* ... Misc APIs ... */
     6362/* ... Misc APIs ... */
     6363/* ... Misc APIs ... */
     6364/* ... Misc APIs ... */
     6365/* ... Misc APIs ... */
     6366/* ... Misc APIs ... */
     6367
     6368
     6369
     6370/**
    63536371 * Query what the VBox status code of the operation is.
    63546372 *
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette