Changeset 22554 in vbox
- Timestamp:
- Aug 28, 2009 2:31:02 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/SSM.cpp
r22480 r22554 242 242 243 243 /** Start structure magic. (Isacc Asimov) */ 244 #define SSMR3STRUCT_BEGIN 0x19200102244 #define SSMR3STRUCT_BEGIN UINT32_C(0x19200102) 245 245 /** End structure magic. (Isacc Asimov) */ 246 #define SSMR3STRUCT_END 0x19920406246 #define SSMR3STRUCT_END UINT32_C(0x19920406) 247 247 248 248 … … 269 269 270 270 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 271 290 /******************************************************************************* 272 291 * Structures and Typedefs * … … 276 295 { 277 296 SSMSTATE_INVALID = 0, 297 SSMSTATE_LIVE_PREP, 298 SSMSTATE_LIVE_EXEC, 299 SSMSTATE_LIVE_VOTE, 278 300 SSMSTATE_SAVE_PREP, 279 301 SSMSTATE_SAVE_EXEC, … … 755 777 static DECLCALLBACK(int) ssmR3SelfLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPhase); 756 778 static int ssmR3Register(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, const char *pszBefore, PSSMUNIT *ppUnit); 779 757 780 static int ssmR3StrmWriteBuffers(PSSMSTRM pStrm); 758 781 static 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 765 783 static 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);770 784 static int ssmR3DataReadRecHdrV2(PSSMHANDLE pSSM); 771 static int ssmR3DataRead(PSSMHANDLE pSSM, void *pvBuf, size_t cbBuf); 785 772 786 773 787 … … 2261 2275 PSSMSTRMBUF pBuf = pStrm->pCur; Assert(pBuf); 2262 2276 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));2265 2277 pStrm->offStreamCRC = pStrm->off; 2266 2278 } … … 2544 2556 / (100 - pSSM->uPercentDone - pSSM->uPercentPrepare); 2545 2557 } 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 */ 2568 static 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 */ 2589 static 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 */ 2603 static 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 */ 2640 static 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 */ 2706 static 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 */ 2737 static 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 */ 2843 static 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 */ 2866 DECLINLINE(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 */ 2892 VMMR3DECL(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 */ 2921 VMMR3DECL(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 */ 2936 VMMR3DECL(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 */ 2950 VMMR3DECL(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 */ 2964 VMMR3DECL(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 */ 2978 VMMR3DECL(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 */ 2992 VMMR3DECL(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 */ 3006 VMMR3DECL(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 */ 3020 VMMR3DECL(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 */ 3034 VMMR3DECL(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 */ 3048 VMMR3DECL(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 */ 3062 VMMR3DECL(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 */ 3076 VMMR3DECL(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 */ 3090 VMMR3DECL(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 */ 3106 VMMR3DECL(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 */ 3120 VMMR3DECL(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 */ 3134 VMMR3DECL(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 */ 3148 VMMR3DECL(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 */ 3162 VMMR3DECL(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 */ 3176 VMMR3DECL(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 */ 3190 VMMR3DECL(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 */ 3204 VMMR3DECL(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 */ 3218 VMMR3DECL(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 */ 3232 VMMR3DECL(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 */ 3247 VMMR3DECL(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 */ 3261 VMMR3DECL(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); 2546 3276 } 2547 3277 … … 2958 3688 2959 3689 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 ... */ 5028 3707 5029 3708 … … 5781 4460 VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool) 5782 4461 { 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); 5785 4463 uint8_t u8; /* see SSMR3PutBool */ 5786 4464 int rc = ssmR3DataRead(pSSM, &u8, sizeof(u8)); … … 5803 4481 VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8) 5804 4482 { 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); 5807 4484 return ssmR3DataRead(pSSM, pu8, sizeof(*pu8)); 5808 4485 } … … 5818 4495 VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8) 5819 4496 { 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); 5822 4498 return ssmR3DataRead(pSSM, pi8, sizeof(*pi8)); 5823 4499 } … … 5833 4509 VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16) 5834 4510 { 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); 5837 4512 return ssmR3DataRead(pSSM, pu16, sizeof(*pu16)); 5838 4513 } … … 5848 4523 VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16) 5849 4524 { 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); 5852 4526 return ssmR3DataRead(pSSM, pi16, sizeof(*pi16)); 5853 4527 } … … 5863 4537 VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32) 5864 4538 { 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); 5867 4540 return ssmR3DataRead(pSSM, pu32, sizeof(*pu32)); 5868 4541 } … … 5878 4551 VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32) 5879 4552 { 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); 5882 4554 return ssmR3DataRead(pSSM, pi32, sizeof(*pi32)); 5883 4555 } … … 5893 4565 VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64) 5894 4566 { 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); 5897 4568 return ssmR3DataRead(pSSM, pu64, sizeof(*pu64)); 5898 4569 } … … 5908 4579 VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64) 5909 4580 { 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); 5912 4582 return ssmR3DataRead(pSSM, pi64, sizeof(*pi64)); 5913 4583 } … … 5923 4593 VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128) 5924 4594 { 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); 5927 4596 return ssmR3DataRead(pSSM, pu128, sizeof(*pu128)); 5928 4597 } … … 5938 4607 VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128) 5939 4608 { 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); 5942 4610 return ssmR3DataRead(pSSM, pi128, sizeof(*pi128)); 5943 4611 } … … 5953 4621 VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu) 5954 4622 { 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); 5957 4624 return ssmR3DataRead(pSSM, pu, sizeof(*pu)); 5958 4625 } … … 5968 4635 VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi) 5969 4636 { 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); 5972 4638 return ssmR3DataRead(pSSM, pi, sizeof(*pi)); 5973 4639 } … … 6013 4679 VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys) 6014 4680 { 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); 6017 4682 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys)); 6018 4683 } … … 6028 4693 VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys) 6029 4694 { 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); 6032 4696 return ssmR3DataRead(pSSM, pGCPhys, sizeof(*pGCPhys)); 6033 4697 } … … 6043 4707 VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys) 6044 4708 { 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); 6047 4710 6048 4711 /* … … 6121 4784 VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr) 6122 4785 { 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); 6125 4787 6126 4788 /* … … 6177 4839 VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr) 6178 4840 { 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); 6181 4842 return ssmR3DataRead(pSSM, pRCPtr, sizeof(*pRCPtr)); 6182 4843 } … … 6192 4853 VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort) 6193 4854 { 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); 6196 4856 return ssmR3DataRead(pSSM, pIOPort, sizeof(*pIOPort)); 6197 4857 } … … 6207 4867 VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel) 6208 4868 { 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); 6211 4870 return ssmR3DataRead(pSSM, pSel, sizeof(*pSel)); 6212 4871 } … … 6223 4882 VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb) 6224 4883 { 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); 6227 4885 return ssmR3DataRead(pSSM, pv, cb); 6228 4886 } … … 6254 4912 VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr) 6255 4913 { 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); 6258 4915 6259 4916 /* read size prefix. */ … … 6285 4942 VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb) 6286 4943 { 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); 6289 4945 while (cb > 0) 6290 4946 { … … 6313 4969 VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM) 6314 4970 { 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); 6317 4972 if (pSSM->u.Read.uFmtVerMajor >= 2) 6318 4973 { … … 6351 5006 6352 5007 /** 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 */ 5016 static 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 */ 5072 static 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 */ 5142 static 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 */ 5431 static 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 */ 5502 static 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 */ 5522 static 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 */ 5696 static 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 */ 5837 VMMR3DECL(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 */ 6011 VMMR3DECL(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 */ 6039 VMMR3DECL(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 */ 6085 VMMR3DECL(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 */ 6119 static 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 */ 6187 static 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 */ 6278 static 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 */ 6319 VMMR3DECL(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 /** 6353 6371 * Query what the VBox status code of the operation is. 6354 6372 *
Note:
See TracChangeset
for help on using the changeset viewer.