VirtualBox

Changeset 1313 in vbox


Ignore:
Timestamp:
Mar 7, 2007 8:22:12 PM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
19278
Message:

Moved the VMM tests into a separate file.

Location:
trunk/src/VBox/VMM
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/Makefile

    r1283 r1313  
    8686        VMReq.cpp \
    8787        VMM.cpp \
     88        VMMTests.cpp \
    8889        HWACCM.cpp \
    8990        VMMAll/CPUMAllRegs.cpp \
  • trunk/src/VBox/VMM/VBoxVMMDeps.cpp

    r23 r1313  
    3131#include <VBox/dbgf.h>
    3232
     33VMMR3DECL(int) VMMDoTest(PVM pVM);
     34
    3335/** Just a dummy global structure containing a bunch of
    3436 * function pointers to code which is wanted in the link.
     
    4648    (PFNRT)PGMInvalidatePage,
    4749    (PFNRT)VMR3Create,
     50    (PFNRT)VMMDoTest,
    4851    NULL
    4952};
  • trunk/src/VBox/VMM/VMM.cpp

    r1286 r1313  
    2020 */
    2121
    22 #if 0 //defined(__AMD64__) && !defined(__WIN__)
    23 # define NO_SUPCALLR0VMM
    24 #endif
     22//#define NO_SUPCALLR0VMM
    2523
    2624/** @page   pg_vmm              VMM - The Virtual Machine Monitor
     
    25592557}
    25602558
    2561 
    2562 /**
    2563  * Performs a testcase.
    2564  *
    2565  * @returns return value from the test.
    2566  * @param   pVM         The VM handle.
    2567  * @param   enmTestcase The testcase operation to perform.
    2568  * @param   uVariation  The testcase variation id.
    2569  */
    2570 static int vmmR3DoGCTest(PVM pVM, VMMGCOPERATION enmTestcase, unsigned uVariation)
    2571 {
    2572     RTGCPTR GCPtrEP;
    2573     int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
    2574     if (VBOX_FAILURE(rc))
    2575         return rc;
    2576 
    2577     CPUMHyperSetCtxCore(pVM, NULL);
    2578     memset(pVM->vmm.s.pbHCStack, 0xaa, VMM_STACK_SIZE);
    2579     CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    2580     CPUMPushHyper(pVM, uVariation);
    2581     CPUMPushHyper(pVM, enmTestcase);
    2582     CPUMPushHyper(pVM, pVM->pVMGC);
    2583     CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));  /* stack frame size */
    2584     CPUMPushHyper(pVM, GCPtrEP);                /* what to call */
    2585     CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    2586     return SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2587 }
    2588 
    2589 
    2590 /**
    2591  * Performs a trap test.
    2592  *
    2593  * @returns Return value from the trap test.
    2594  * @param   pVM         The VM handle.
    2595  * @param   u8Trap      The trap number to test.
    2596  * @param   uVariation  The testcase variation.
    2597  * @param   rcExpect    The expected result.
    2598  * @param   u32Eax      The expected eax value.
    2599  * @param   pszFaultEIP The fault address. Pass NULL if this isn't available or doesn't apply.
    2600  * @param   pszDesc     The test description.
    2601  */
    2602 static int vmmR3DoTrapTest(PVM pVM, uint8_t u8Trap, unsigned uVariation, int rcExpect, uint32_t u32Eax, const char *pszFaultEIP, const char *pszDesc)
    2603 {
    2604     RTPrintf("VMM: testing 0%x / %d - %s\n", u8Trap, uVariation, pszDesc);
    2605 
    2606     RTGCPTR GCPtrEP;
    2607     int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
    2608     if (VBOX_FAILURE(rc))
    2609         return rc;
    2610 
    2611     CPUMHyperSetCtxCore(pVM, NULL);
    2612     memset(pVM->vmm.s.pbHCStack, 0xaa, VMM_STACK_SIZE);
    2613     CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    2614     CPUMPushHyper(pVM, uVariation);
    2615     CPUMPushHyper(pVM, u8Trap + VMMGC_DO_TESTCASE_TRAP_FIRST);
    2616     CPUMPushHyper(pVM, pVM->pVMGC);
    2617     CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));  /* stack frame size */
    2618     CPUMPushHyper(pVM, GCPtrEP);                /* what to call */
    2619     CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    2620     rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2621     bool fDump = false;
    2622     if (rc != rcExpect)
    2623     {
    2624         RTPrintf("VMM: FAILURE - rc=%Vrc expected %Vrc\n", rc, rcExpect);
    2625         if (rc != VERR_NOT_IMPLEMENTED)
    2626             fDump = true;
    2627     }
    2628     else if (    rcExpect != VINF_SUCCESS
    2629              &&  u8Trap != 8 /* double fault doesn't dare set TrapNo. */
    2630              &&  u8Trap != 3 /* guest only, we're not in guest. */
    2631              &&  u8Trap != 1 /* guest only, we're not in guest. */
    2632              &&  u8Trap != TRPMGetTrapNo(pVM))
    2633     {
    2634         RTPrintf("VMM: FAILURE - Trap %#x expected %#x\n", TRPMGetTrapNo(pVM), u8Trap);
    2635         fDump = true;
    2636     }
    2637     else if (pszFaultEIP)
    2638     {
    2639         RTGCPTR GCPtrFault;
    2640         int rc2 = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, pszFaultEIP, &GCPtrFault);
    2641         if (VBOX_FAILURE(rc2))
    2642             RTPrintf("VMM: FAILURE - Failed to resolve symbol '%s', %Vrc!\n", pszFaultEIP, rc);
    2643         else if (GCPtrFault != CPUMGetHyperEIP(pVM))
    2644         {
    2645             RTPrintf("VMM: FAILURE - EIP=%VGv expected %VGv (%s)\n", CPUMGetHyperEIP(pVM), GCPtrFault, pszFaultEIP);
    2646             fDump = true;
    2647         }
    2648     }
    2649     else if (rcExpect != VINF_SUCCESS)
    2650     {
    2651         if (CPUMGetHyperSS(pVM) == SELMGetHyperDS(pVM))
    2652             RTPrintf("VMM: FAILURE - ss=%x expected %x\n", CPUMGetHyperSS(pVM), SELMGetHyperDS(pVM));
    2653         if (CPUMGetHyperES(pVM) == SELMGetHyperDS(pVM))
    2654             RTPrintf("VMM: FAILURE - es=%x expected %x\n", CPUMGetHyperES(pVM), SELMGetHyperDS(pVM));
    2655         if (CPUMGetHyperDS(pVM) == SELMGetHyperDS(pVM))
    2656             RTPrintf("VMM: FAILURE - ds=%x expected %x\n", CPUMGetHyperDS(pVM), SELMGetHyperDS(pVM));
    2657         if (CPUMGetHyperFS(pVM) == SELMGetHyperDS(pVM))
    2658             RTPrintf("VMM: FAILURE - fs=%x expected %x\n", CPUMGetHyperFS(pVM), SELMGetHyperDS(pVM));
    2659         if (CPUMGetHyperGS(pVM) == SELMGetHyperDS(pVM))
    2660             RTPrintf("VMM: FAILURE - gs=%x expected %x\n", CPUMGetHyperGS(pVM), SELMGetHyperDS(pVM));
    2661         if (CPUMGetHyperEDI(pVM) == 0x01234567)
    2662             RTPrintf("VMM: FAILURE - edi=%x expected %x\n", CPUMGetHyperEDI(pVM), 0x01234567);
    2663         if (CPUMGetHyperESI(pVM) == 0x42000042)
    2664             RTPrintf("VMM: FAILURE - esi=%x expected %x\n", CPUMGetHyperESI(pVM), 0x42000042);
    2665         if (CPUMGetHyperEBP(pVM) == 0xffeeddcc)
    2666             RTPrintf("VMM: FAILURE - ebp=%x expected %x\n", CPUMGetHyperEBP(pVM), 0xffeeddcc);
    2667         if (CPUMGetHyperEBX(pVM) == 0x89abcdef)
    2668             RTPrintf("VMM: FAILURE - ebx=%x expected %x\n", CPUMGetHyperEBX(pVM), 0x89abcdef);
    2669         if (CPUMGetHyperECX(pVM) == 0xffffaaaa)
    2670             RTPrintf("VMM: FAILURE - ecx=%x expected %x\n", CPUMGetHyperECX(pVM), 0xffffaaaa);
    2671         if (CPUMGetHyperEDX(pVM) == 0x77778888)
    2672             RTPrintf("VMM: FAILURE - edx=%x expected %x\n", CPUMGetHyperEDX(pVM), 0x77778888);
    2673         if (CPUMGetHyperEAX(pVM) == u32Eax)
    2674             RTPrintf("VMM: FAILURE - eax=%x expected %x\n", CPUMGetHyperEAX(pVM), u32Eax);
    2675     }
    2676     if (fDump)
    2677         VMMR3FatalDump(pVM, rc);
    2678     return rc;
    2679 }
    2680 
    2681 
    2682 /* execute the switch. */
    2683 VMMR3DECL(int) VMMDoTest(PVM pVM)
    2684 {
    2685 #if 1
    2686 #ifdef NO_SUPCALLR0VMM
    2687     RTPrintf("NO_SUPCALLR0VMM\n");
    2688     return VINF_SUCCESS;
    2689 #endif
    2690 
    2691     /*
    2692      * Setup stack for calling VMMGCEntry().
    2693      */
    2694     RTGCPTR GCPtrEP;
    2695     int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
    2696     if (VBOX_SUCCESS(rc))
    2697     {
    2698         RTPrintf("VMM: VMMGCEntry=%VGv\n", GCPtrEP);
    2699 
    2700         /*
    2701          * Test various crashes which we must be able to recover from.
    2702          */
    2703         vmmR3DoTrapTest(pVM, 0x3, 0, VINF_EM_DBG_HYPER_ASSERTION,  0xf0f0f0f0, "vmmGCTestTrap3_FaultEIP", "int3");
    2704         vmmR3DoTrapTest(pVM, 0x3, 1, VINF_EM_DBG_HYPER_ASSERTION,  0xf0f0f0f0, "vmmGCTestTrap3_FaultEIP", "int3 WP");
    2705 
    2706 #if defined(DEBUG_bird) /* guess most people would like to skip these since they write to com1. */
    2707         vmmR3DoTrapTest(pVM, 0x8, 0, VERR_TRPM_PANIC,       0x00000000, "vmmGCTestTrap8_FaultEIP", "#DF [#PG]");
    2708         SELMR3Relocate(pVM); /* this resets the busy flag of the Trap 08 TSS */
    2709         bool f;
    2710         rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "DoubleFault", &f);
    2711 #if !defined(DEBUG_bird)
    2712         if (VBOX_SUCCESS(rc) && f)
    2713 #endif
    2714         {
    2715             /* see tripple fault warnings in SELM and VMMGC.cpp. */
    2716             vmmR3DoTrapTest(pVM, 0x8, 1, VERR_TRPM_PANIC,       0x00000000, "vmmGCTestTrap8_FaultEIP", "#DF [#PG] WP");
    2717             SELMR3Relocate(pVM); /* this resets the busy flag of the Trap 08 TSS */
    2718         }
    2719 #endif
    2720 
    2721         vmmR3DoTrapTest(pVM, 0xd, 0, VERR_TRPM_DONT_PANIC,  0xf0f0f0f0, "vmmGCTestTrap0d_FaultEIP", "ltr #GP");
    2722         ///@todo find a better \#GP case, on intel ltr will \#PF (busy update?) and not \#GP.
    2723         //vmmR3DoTrapTest(pVM, 0xd, 1, VERR_TRPM_DONT_PANIC,  0xf0f0f0f0, "vmmGCTestTrap0d_FaultEIP", "ltr #GP WP");
    2724 
    2725         vmmR3DoTrapTest(pVM, 0xe, 0, VERR_TRPM_DONT_PANIC,  0x00000000, "vmmGCTestTrap0e_FaultEIP", "#PF (NULL)");
    2726         vmmR3DoTrapTest(pVM, 0xe, 1, VERR_TRPM_DONT_PANIC,  0x00000000, "vmmGCTestTrap0e_FaultEIP", "#PF (NULL) WP");
    2727         vmmR3DoTrapTest(pVM, 0xe, 2, VINF_SUCCESS,          0x00000000, NULL,                       "#PF w/Tmp Handler");
    2728         vmmR3DoTrapTest(pVM, 0xe, 4, VINF_SUCCESS,          0x00000000, NULL,                       "#PF w/Tmp Handler and bad fs");
    2729 
    2730         /*
    2731          * Set a debug register and perform a context switch.
    2732          */
    2733         rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
    2734         if (rc != VINF_SUCCESS)
    2735         {
    2736             RTPrintf("VMM: Nop test failed, rc=%Vrc not VINF_SUCCESS\n", rc);
    2737             return rc;
    2738         }
    2739 
    2740         /* a harmless breakpoint */
    2741         RTPrintf("VMM: testing hardware bp at 0x10000 (not hit)\n");
    2742         DBGFADDRESS Addr;
    2743         DBGFR3AddrFromFlat(pVM, &Addr, 0x10000);
    2744         RTUINT iBp0;
    2745         rc = DBGFR3BpSetReg(pVM, &Addr, 0,  ~(uint64_t)0, X86_DR7_RW_EO, 1, &iBp0);
    2746         AssertReleaseRC(rc);
    2747         rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
    2748         if (rc != VINF_SUCCESS)
    2749         {
    2750             RTPrintf("VMM: DR0=0x10000 test failed with rc=%Vrc!\n", rc);
    2751             return rc;
    2752         }
    2753 
    2754         /* a bad one at VMMGCEntry */
    2755         RTPrintf("VMM: testing hardware bp at VMMGCEntry (hit)\n");
    2756         DBGFR3AddrFromFlat(pVM, &Addr, GCPtrEP);
    2757         RTUINT iBp1;
    2758         rc = DBGFR3BpSetReg(pVM, &Addr, 0,  ~(uint64_t)0, X86_DR7_RW_EO, 1, &iBp1);
    2759         AssertReleaseRC(rc);
    2760         rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
    2761         if (rc != VINF_EM_DBG_HYPER_BREAKPOINT)
    2762         {
    2763             RTPrintf("VMM: DR1=VMMGCEntry test failed with rc=%Vrc! expected VINF_EM_RAW_BREAKPOINT_HYPER\n", rc);
    2764             return rc;
    2765         }
    2766 
    2767         /* resume the breakpoint */
    2768         RTPrintf("VMM: resuming hyper after breakpoint\n");
    2769         CPUMSetHyperEFlags(pVM, CPUMGetHyperEFlags(pVM) | X86_EFL_RF);
    2770         rc = VMMR3ResumeHyper(pVM);
    2771         if (rc != VINF_SUCCESS)
    2772         {
    2773             RTPrintf("VMM: failed to resume on hyper breakpoint, rc=%Vrc\n", rc);
    2774             return rc;
    2775         }
    2776 
    2777         /* engage the breakpoint again and try single stepping. */
    2778         RTPrintf("VMM: testing hardware bp at VMMGCEntry + stepping\n");
    2779         rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
    2780         if (rc != VINF_EM_DBG_HYPER_BREAKPOINT)
    2781         {
    2782             RTPrintf("VMM: DR1=VMMGCEntry test failed with rc=%Vrc! expected VINF_EM_RAW_BREAKPOINT_HYPER\n", rc);
    2783             return rc;
    2784         }
    2785 
    2786         RTGCUINTREG OldPc = CPUMGetHyperEIP(pVM);
    2787         RTPrintf("%RGr=>", OldPc);
    2788         unsigned i;
    2789         for (i = 0; i < 8; i++)
    2790         {
    2791             CPUMSetHyperEFlags(pVM, CPUMGetHyperEFlags(pVM) | X86_EFL_TF | X86_EFL_RF);
    2792             rc = VMMR3ResumeHyper(pVM);
    2793             if (rc != VINF_EM_DBG_HYPER_STEPPED)
    2794             {
    2795                 RTPrintf("\nVMM: failed to step on hyper breakpoint, rc=%Vrc\n", rc);
    2796                 return rc;
    2797             }
    2798             RTGCUINTREG Pc = CPUMGetHyperEIP(pVM);
    2799             RTPrintf("%RGr=>", Pc);
    2800             if (Pc == OldPc)
    2801             {
    2802                 RTPrintf("\nVMM: step failed, PC: %RGr -> %RGr\n", OldPc, Pc);
    2803                 return VERR_GENERAL_FAILURE;
    2804             }
    2805             OldPc = Pc;
    2806         }
    2807         RTPrintf("ok\n");
    2808 
    2809         /* done, clear it */
    2810         if (    VBOX_FAILURE(DBGFR3BpClear(pVM, iBp0))
    2811             ||  VBOX_FAILURE(DBGFR3BpClear(pVM, iBp1)))
    2812         {
    2813             RTPrintf("VMM: Failed to clear breakpoints!\n");
    2814             return VERR_GENERAL_FAILURE;
    2815         }
    2816         rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_NOP, 0);
    2817         if (rc != VINF_SUCCESS)
    2818         {
    2819             RTPrintf("VMM: NOP failed, rc=%Vrc\n", rc);
    2820             return rc;
    2821         }
    2822 
    2823         /*
    2824          * Interrupt masking.
    2825          */
    2826         RTPrintf("VMM: interrupt masking...\n"); RTStrmFlush(g_pStdOut); RTThreadSleep(250);
    2827         for (i = 0; i < 10000; i++)
    2828         {
    2829             uint64_t StartTick = ASMReadTSC();
    2830             rc = vmmR3DoGCTest(pVM, VMMGC_DO_TESTCASE_INTERRUPT_MASKING, 0);
    2831             if (rc != VINF_SUCCESS)
    2832             {
    2833                 RTPrintf("VMM: Interrupt masking failed: rc=%Vrc\n", rc);
    2834                 return rc;
    2835             }
    2836             uint64_t Ticks = ASMReadTSC() - StartTick;
    2837             if (Ticks < (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000))
    2838                 RTPrintf("Warning: Ticks=%RU64 (< %RU64)\n", Ticks, SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) / 10000);
    2839         }
    2840 
    2841         /*
    2842          * Interrupt forwarding.
    2843          */
    2844         CPUMHyperSetCtxCore(pVM, NULL);
    2845         CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    2846         CPUMPushHyper(pVM, 0);
    2847         CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_HYPER_INTERRUPT);
    2848         CPUMPushHyper(pVM, pVM->pVMGC);
    2849         CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));  /* stack frame size */
    2850         CPUMPushHyper(pVM, GCPtrEP);                /* what to call */
    2851         CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    2852         Log(("trampoline=%x\n", pVM->vmm.s.pfnGCCallTrampoline));
    2853 
    2854         /*
    2855          * Switch and do da thing.
    2856          */
    2857         RTPrintf("VMM: interrupt forwarding...\n"); RTStrmFlush(g_pStdOut); RTThreadSleep(250);
    2858         i = 0;
    2859         uint64_t    tsBegin = RTTimeNanoTS();
    2860         uint64_t    TickStart = ASMReadTSC();
    2861         do
    2862         {
    2863             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2864             if (VBOX_FAILURE(rc))
    2865             {
    2866                 Log(("VMM: GC returned fatal %Vra in iteration %d\n", rc, i));
    2867                 VMMR3FatalDump(pVM, rc);
    2868                 return rc;
    2869             }
    2870             i++;
    2871             if (!(i % 32))
    2872                 Log(("VMM: iteration %d, esi=%08x edi=%08x ebx=%08x\n",
    2873                        i, CPUMGetHyperESI(pVM), CPUMGetHyperEDI(pVM), CPUMGetHyperEBX(pVM)));
    2874         } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
    2875         uint64_t    TickEnd = ASMReadTSC();
    2876         uint64_t    tsEnd = RTTimeNanoTS();
    2877 
    2878         uint64_t    Elapsed = tsEnd - tsBegin;
    2879         uint64_t    PerIteration = Elapsed / (uint64_t)i;
    2880         uint64_t    cTicksElapsed = TickEnd - TickStart;
    2881         uint64_t    cTicksPerIteration = cTicksElapsed / (uint64_t)i;
    2882 
    2883         RTPrintf("VMM: %8d interrupts in %11llu ns (%11llu ticks),  %10llu ns/iteration (%11llu ticks)\n",
    2884                  i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration);
    2885         Log(("VMM: %8d interrupts in %11llu ns (%11llu ticks),  %10llu ns/iteration (%11llu ticks)\n",
    2886              i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration));
    2887 
    2888         /*
    2889          * These forced actions are not necessary for the test and trigger breakpoints too.
    2890          */
    2891         VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
    2892         VM_FF_CLEAR(pVM, VM_FF_SELM_SYNC_TSS);
    2893 
    2894         /*
    2895          * Profile switching.
    2896          */
    2897         RTPrintf("VMM: profiling switcher...\n");
    2898         Log(("VMM: profiling switcher...\n"));
    2899         uint64_t TickMin = ~0;
    2900         tsBegin = RTTimeNanoTS();
    2901         TickStart = ASMReadTSC();
    2902         for (i = 0; i < 1000000; i++)
    2903         {
    2904             CPUMHyperSetCtxCore(pVM, NULL);
    2905             CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    2906             CPUMPushHyper(pVM, 0);
    2907             CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_NOP);
    2908             CPUMPushHyper(pVM, pVM->pVMGC);
    2909             CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));    /* stack frame size */
    2910             CPUMPushHyper(pVM, GCPtrEP);                /* what to call */
    2911             CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    2912 
    2913             uint64_t TickThisStart = ASMReadTSC();
    2914             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2915             uint64_t TickThisElapsed = ASMReadTSC() - TickThisStart;
    2916             if (VBOX_FAILURE(rc))
    2917             {
    2918                 Log(("VMM: GC returned fatal %Vra in iteration %d\n", rc, i));
    2919                 VMMR3FatalDump(pVM, rc);
    2920                 return rc;
    2921             }
    2922             if (TickThisElapsed < TickMin)
    2923                 TickMin = TickThisElapsed;
    2924         }
    2925         TickEnd = ASMReadTSC();
    2926         tsEnd = RTTimeNanoTS();
    2927 
    2928         Elapsed = tsEnd - tsBegin;
    2929         PerIteration = Elapsed / (uint64_t)i;
    2930         cTicksElapsed = TickEnd - TickStart;
    2931         cTicksPerIteration = cTicksElapsed / (uint64_t)i;
    2932 
    2933         RTPrintf("VMM: %8d cycles     in %11llu ns (%11lld ticks),  %10llu ns/iteration (%11lld ticks)  Min %11lld ticks\n",
    2934                  i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin);
    2935         Log(("VMM: %8d cycles     in %11llu ns (%11lld ticks),  %10llu ns/iteration (%11lld ticks)  Min %11lld ticks\n",
    2936              i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin));
    2937 
    2938         rc = VINF_SUCCESS;
    2939     }
    2940     else
    2941         AssertMsgFailed(("Failed to resolved VMMGC.gc::VMMGCEntry(), rc=%Vrc\n", rc));
    2942 #endif
    2943     return rc;
    2944 }
    2945 
    2946 #define SYNC_SEL(pHyperCtx, reg)                                                        \
    2947         if (pHyperCtx->reg)                                                             \
    2948         {                                                                               \
    2949             SELMSELINFO selInfo;                                                        \
    2950             int rc = SELMR3GetShadowSelectorInfo(pVM, pHyperCtx->reg, &selInfo);        \
    2951             AssertRC(rc);                                                               \
    2952                                                                                         \
    2953             pHyperCtx->reg##Hid.u32Base              = selInfo.GCPtrBase;               \
    2954             pHyperCtx->reg##Hid.u32Limit             = selInfo.cbLimit;                 \
    2955             pHyperCtx->reg##Hid.Attr.n.u1Present     = selInfo.Raw.Gen.u1Present;       \
    2956             pHyperCtx->reg##Hid.Attr.n.u1DefBig      = selInfo.Raw.Gen.u1DefBig;        \
    2957             pHyperCtx->reg##Hid.Attr.n.u1Granularity = selInfo.Raw.Gen.u1Granularity;   \
    2958             pHyperCtx->reg##Hid.Attr.n.u4Type        = selInfo.Raw.Gen.u4Type;          \
    2959             pHyperCtx->reg##Hid.Attr.n.u2Dpl         = selInfo.Raw.Gen.u2Dpl;           \
    2960             pHyperCtx->reg##Hid.Attr.n.u1DescType    = selInfo.Raw.Gen.u1DescType;      \
    2961             pHyperCtx->reg##Hid.Attr.n.u1Reserved    = selInfo.Raw.Gen.u1Reserved;      \
    2962         }
    2963 
    2964 /* execute the switch. */
    2965 VMMR3DECL(int) VMMDoHwAccmTest(PVM pVM)
    2966 {
    2967     uint32_t i;
    2968     int      rc;
    2969     PCPUMCTX pHyperCtx, pGuestCtx;
    2970     RTGCPHYS CR3Phys = 0x0; /* fake address */
    2971 
    2972     if (!HWACCMR3IsAllowed(pVM))
    2973     {
    2974         RTPrintf("VMM: Hardware accelerated test not available!\n");
    2975         return VERR_ACCESS_DENIED;
    2976     }
    2977 
    2978     /*
    2979      * These forced actions are not necessary for the test and trigger breakpoints too.
    2980      */
    2981     VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
    2982     VM_FF_CLEAR(pVM, VM_FF_SELM_SYNC_TSS);
    2983 
    2984     /* Enable mapping of the hypervisor into the shadow page table. */
    2985     PGMR3ChangeShwPDMappings(pVM, true);
    2986 
    2987     CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
    2988 
    2989     pHyperCtx->cr0 = X86_CR0_PE | X86_CR0_WP | X86_CR0_PG | X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
    2990     pHyperCtx->cr4 = X86_CR4_PGE | X86_CR4_OSFSXR | X86_CR4_OSXMMEEXCPT;
    2991     PGMChangeMode(pVM, pHyperCtx->cr0, pHyperCtx->cr4, 0);
    2992     PGMSyncCR3(pVM, pHyperCtx->cr0, CR3Phys, pHyperCtx->cr4, true);
    2993 
    2994     VM_FF_CLEAR(pVM, VM_FF_TO_R3);
    2995     VM_FF_CLEAR(pVM, VM_FF_TIMER);
    2996     VM_FF_CLEAR(pVM, VM_FF_REQUEST);
    2997 
    2998     /*
    2999      * Setup stack for calling VMMGCEntry().
    3000      */
    3001     RTGCPTR GCPtrEP;
    3002     rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
    3003     if (VBOX_SUCCESS(rc))
    3004     {
    3005         RTPrintf("VMM: VMMGCEntry=%VGv\n", GCPtrEP);
    3006 
    3007         CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
    3008 
    3009         /* Fill in hidden selector registers for the hypervisor state. */
    3010         SYNC_SEL(pHyperCtx, cs);
    3011         SYNC_SEL(pHyperCtx, ds);
    3012         SYNC_SEL(pHyperCtx, es);
    3013         SYNC_SEL(pHyperCtx, fs);
    3014         SYNC_SEL(pHyperCtx, gs);
    3015         SYNC_SEL(pHyperCtx, ss);
    3016         SYNC_SEL(pHyperCtx, tr);
    3017 
    3018         /*
    3019          * Profile switching.
    3020          */
    3021         RTPrintf("VMM: profiling switcher...\n");
    3022         Log(("VMM: profiling switcher...\n"));
    3023         uint64_t TickMin = ~0;
    3024         uint64_t tsBegin = RTTimeNanoTS();
    3025         uint64_t TickStart = ASMReadTSC();
    3026         for (i = 0; i < 1000000; i++)
    3027         {
    3028             CPUMHyperSetCtxCore(pVM, NULL);
    3029 
    3030             CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    3031             CPUMPushHyper(pVM, 0);
    3032             CPUMPushHyper(pVM, VMMGC_DO_TESTCASE_HWACCM_NOP);
    3033             CPUMPushHyper(pVM, pVM->pVMGC);
    3034             CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));    /* stack frame size */
    3035             CPUMPushHyper(pVM, GCPtrEP);                /* what to call */
    3036             CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    3037 
    3038             CPUMQueryHyperCtxPtr(pVM, &pHyperCtx);
    3039             CPUMQueryGuestCtxPtr(pVM, &pGuestCtx);
    3040 
    3041             /* Copy the hypervisor context to make sure we have a valid guest context. */
    3042             *pGuestCtx = *pHyperCtx;
    3043             pGuestCtx->cr3 = CR3Phys;
    3044 
    3045             VM_FF_CLEAR(pVM, VM_FF_TO_R3);
    3046             VM_FF_CLEAR(pVM, VM_FF_TIMER);
    3047 
    3048             uint64_t TickThisStart = ASMReadTSC();
    3049             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_HWACC_RUN, NULL);
    3050             uint64_t TickThisElapsed = ASMReadTSC() - TickThisStart;
    3051             if (VBOX_FAILURE(rc))
    3052             {
    3053                 Log(("VMM: GC returned fatal %Vra in iteration %d\n", rc, i));
    3054                 VMMR3FatalDump(pVM, rc);
    3055                 return rc;
    3056             }
    3057             if (TickThisElapsed < TickMin)
    3058                 TickMin = TickThisElapsed;
    3059         }
    3060         uint64_t TickEnd = ASMReadTSC();
    3061         uint64_t tsEnd = RTTimeNanoTS();
    3062 
    3063         uint64_t Elapsed = tsEnd - tsBegin;
    3064         uint64_t PerIteration = Elapsed / (uint64_t)i;
    3065         uint64_t cTicksElapsed = TickEnd - TickStart;
    3066         uint64_t cTicksPerIteration = cTicksElapsed / (uint64_t)i;
    3067 
    3068         RTPrintf("VMM: %8d cycles     in %11llu ns (%11lld ticks),  %10llu ns/iteration (%11lld ticks)  Min %11lld ticks\n",
    3069                  i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin);
    3070         Log(("VMM: %8d cycles     in %11llu ns (%11lld ticks),  %10llu ns/iteration (%11lld ticks)  Min %11lld ticks\n",
    3071              i, Elapsed, cTicksElapsed, PerIteration, cTicksPerIteration, TickMin));
    3072 
    3073         rc = VINF_SUCCESS;
    3074     }
    3075     else
    3076         AssertMsgFailed(("Failed to resolved VMMGC.gc::VMMGCEntry(), rc=%Vrc\n", rc));
    3077 
    3078     return rc;
    3079 }
  • trunk/src/VBox/VMM/VMMTests.cpp

    r1307 r1313  
    11/* $Id$ */
    22/** @file
    3  * VMM - The Virtual Machine Monitor Core.
     3 * VMM - The Virtual Machine Monitor Core, Tests.
    44 */
    55
     
    2020 */
    2121
    22 #if 0 //defined(__AMD64__) && !defined(__WIN__)
    23 # define NO_SUPCALLR0VMM
    24 #endif
    25 
    26 /** @page   pg_vmm              VMM - The Virtual Machine Monitor
    27  *
    28  * !Revise this! It's already incorrect!
    29  *
    30  * The Virtual Machine Monitor (VMM) is the core of the virtual machine. It
    31  * manages the alternate reality; controlling the virtualization, managing
    32  * resources, tracking CPU state, it's resources and so on...
    33  *
    34  * We will split the VMM into smaller entities:
    35  *
    36  *      - Virtual Machine Core Monitor (VMCM), which purpose it is to
    37  *        provide ring and world switching, that including routing
    38  *        interrupts to the host OS and traps to the appropriate trap
    39  *        handlers. It will implement an external interface for
    40  *        managing trap handlers.
    41  *
    42  *      - CPU Monitor (CM), tracking the state of the CPU (in the alternate
    43  *        reality) and implementing external interfaces to read and change
    44  *        the state.
    45  *
    46  *      - Memory Monitor (MM), which purpose it is to virtualize physical
    47  *        pages, segment descriptor tables, interrupt descriptor tables, task
    48  *        segments, and keep track of all memory providing external interfaces
    49  *        to access content and map pages. (Internally splitt into smaller entities!)
    50  *
    51  *      - IO Monitor (IOM), which virtualizes in and out I/O operations. It
    52  *        interacts with the MM to implement memory mapped I/O. External
    53  *        interfaces for adding and removing I/O ranges are implemented.
    54  *
    55  *      - External Interrupt Monitor (EIM), which purpose it is to manage
    56  *        interrupts generated by virtual devices. This monitor provides
    57  *        an interfaces for raising interrupts which is accessible at any
    58  *        time and from all thread.
    59  *        <p>
    60  *        A subentity of the EIM is the vitual Programmable Interrupt
    61  *        Controller Device (VPICD), and perhaps a virtual I/O Advanced
    62  *        Programmable Interrupt Controller Device (VAPICD).
    63  *
    64  *      - Direct Memory Access Monitor (DMAM), which purpose it is to support
    65  *        virtual device using the DMA controller. Interfaces must be as the
    66  *        EIM interfaces independent and threadable.
    67  *        <p>
    68  *        A subentity of the DMAM is a virtual DMA Controller Device (VDMACD).
    69  *
    70  *
    71  * Entities working on a higher level:
    72  *
    73  *      - Device Manager (DM), which is a support facility for virtualized
    74  *        hardware. This provides generic facilities for efficient device
    75  *        virtualization. It will manage device attaching and detaching
    76  *        conversing with EIM and IOM.
    77  *
    78  *      - Debugger Facility (DBGF) provides the basic features for
    79  *        debugging the alternate reality execution.
    80  *
    81  *
    82  *
    83  * @section pg_vmm_s_use_cases          Use Cases
    84  *
    85  * @subsection  pg_vmm_s_use_case_boot  Bootstrap
    86  *
    87  *  - Basic Init:
    88  *      - Init SUPDRV.
    89  *
    90  *  - Init Virtual Machine Instance:
    91  *      - Load settings.
    92  *      - Check resource requirements (memory, com, stuff).
    93  *
    94  *  - Init Host Ring 3 part:
    95  *      - Init Core code.
    96  *      - Load Pluggable Components.
    97  *      - Init Pluggable Components.
    98  *
    99  *  - Init Host Ring 0 part:
    100  *      - Load Core (core = core components like VMM, RMI, CA, and so on) code.
    101  *      - Init Core code.
    102  *      - Load Pluggable Component code.
    103  *      - Init Pluggable Component code.
    104  *
    105  *  - Allocate first chunk of memory and pin it down. This block of memory
    106  *    will fit the following pieces:
    107  *      - Virtual Machine Instance data. (Config, CPU state, VMM state, ++)
    108  *        (This is available from everywhere (at different addresses though)).
    109  *      - VMM Guest Context code.
    110  *      - Pluggable devices Guest Context code.
    111  *      - Page tables (directory and everything) for the VMM Guest
    112  *
    113  *  - Setup Guest (Ring 0) part:
    114  *      - Setup initial page tables (i.e. directory all the stuff).
    115  *      - Load Core Guest Context code.
    116  *      - Load Pluggable Devices Guest Context code.
    117  *
    118  *
    119  */
    120 
     22//#define NO_SUPCALLR0VMM
    12123
    12224/*******************************************************************************
     
    12527#define LOG_GROUP LOG_GROUP_VMM
    12628#include <VBox/vmm.h>
    127 #include <VBox/vmapi.h>
    128 #include <VBox/pgm.h>
    129 #include <VBox/cfgm.h>
    13029#include <VBox/pdm.h>
    13130#include <VBox/cpum.h>
    13231#include <VBox/mm.h>
    133 #include <VBox/iom.h>
    13432#include <VBox/trpm.h>
    13533#include <VBox/selm.h>
    136 #include <VBox/em.h>
    137 #include <VBox/sup.h>
    138 #include <VBox/dbgf.h>
    139 #include <VBox/csam.h>
    140 #include <VBox/patm.h>
    141 #include <VBox/rem.h>
    142 #include <VBox/ssm.h>
    143 #include <VBox/tm.h>
    14434#include "VMMInternal.h"
    145 #include "VMMSwitcher/VMMSwitcher.h"
    14635#include <VBox/vm.h>
    14736#include <VBox/err.h>
    14837#include <VBox/param.h>
    149 #include <VBox/version.h>
    15038#include <VBox/x86.h>
    15139#include <VBox/hwaccm.h>
     40
    15241#include <iprt/assert.h>
    153 #include <iprt/alloc.h>
    15442#include <iprt/asm.h>
    15543#include <iprt/time.h>
    15644#include <iprt/stream.h>
    15745#include <iprt/string.h>
    158 #include <iprt/stdarg.h>
    159 #include <iprt/ctype.h>
    160 
    161 
    162 
    163 /** The saved state version. */
    164 #define VMM_SAVED_STATE_VERSION     3
    165 
    166 
    167 /*******************************************************************************
    168 *   Internal Functions                                                         *
    169 *******************************************************************************/
    170 static DECLCALLBACK(int) vmmR3Save(PVM pVM, PSSMHANDLE pSSM);
    171 static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
    172 static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser);
    173 static int vmmR3ServiceCallHostRequest(PVM pVM);
    174 
    175 
    176 /*******************************************************************************
    177 *   Global Variables                                                           *
    178 *******************************************************************************/
    179 /** Array of switcher defininitions.
    180  * The type and index shall match!
    181  */
    182 static PVMMSWITCHERDEF s_apSwitchers[VMMSWITCHER_MAX] =
    183 {
    184     NULL, /* invalid entry */
    185 #ifndef __AMD64__
    186     &vmmR3Switcher32BitTo32Bit_Def,
    187     &vmmR3Switcher32BitToPAE_Def,
    188     NULL,   //&vmmR3Switcher32BitToAMD64_Def,
    189     &vmmR3SwitcherPAETo32Bit_Def,
    190     &vmmR3SwitcherPAEToPAE_Def,
    191     NULL,   //&vmmR3SwitcherPAEToAMD64_Def,
    192 # ifdef VBOX_WITH_HYBIRD_32BIT_KERNEL
    193     &vmmR3SwitcherAMD64ToPAE_Def,
    194 # else
    195     NULL,   //&vmmR3SwitcherAMD64ToPAE_Def,
    196 # endif
    197     NULL    //&vmmR3SwitcherAMD64ToAMD64_Def,
    198 #else
    199     NULL,   //&vmmR3Switcher32BitTo32Bit_Def,
    200     NULL,   //&vmmR3Switcher32BitToPAE_Def,
    201     NULL,   //&vmmR3Switcher32BitToAMD64_Def,
    202     NULL,   //&vmmR3SwitcherPAETo32Bit_Def,
    203     NULL,   //&vmmR3SwitcherPAEToPAE_Def,
    204     NULL,   //&vmmR3SwitcherPAEToAMD64_Def,
    205     &vmmR3SwitcherAMD64ToPAE_Def,
    206     NULL    //&vmmR3SwitcherAMD64ToAMD64_Def,
    207 #endif
    208 };
    209 
    210 
    211 
    212 /**
    213  * Initiates the core code.
    214  *
    215  * This is core per VM code which might need fixups and/or for ease of use
    216  * are put on linear contiguous backing.
    217  *
    218  * @returns VBox status code.
    219  * @param   pVM     Pointer to VM structure.
    220  */
    221 static int vmmR3InitCoreCode(PVM pVM)
    222 {
    223     /*
    224      * Calc the size.
    225      */
    226     unsigned cbCoreCode = 0;
    227     for (unsigned iSwitcher = 0; iSwitcher < ELEMENTS(s_apSwitchers); iSwitcher++)
    228     {
    229         pVM->vmm.s.aoffSwitchers[iSwitcher] = cbCoreCode;
    230         PVMMSWITCHERDEF pSwitcher = s_apSwitchers[iSwitcher];
    231         if (pSwitcher)
    232         {
    233             AssertRelease((unsigned)pSwitcher->enmType == iSwitcher);
    234             cbCoreCode += RT_ALIGN_32(pSwitcher->cbCode + 1, 32);
    235         }
    236     }
    237 
    238     /*
    239      * Allocate continguous pages for switchers and deal with
    240      * conflicts in the intermediate mapping of the code.
    241      */
    242     pVM->vmm.s.cbCoreCode = RT_ALIGN_32(cbCoreCode, PAGE_SIZE);
    243     pVM->vmm.s.pvHCCoreCodeR3 = SUPContAlloc2(pVM->vmm.s.cbCoreCode, &pVM->vmm.s.pvHCCoreCodeR0, &pVM->vmm.s.HCPhysCoreCode);
    244     int rc = VERR_NO_MEMORY;
    245     if (pVM->vmm.s.pvHCCoreCodeR3)
    246     {
    247         rc = PGMR3MapIntermediate(pVM, pVM->vmm.s.pvHCCoreCodeR0, pVM->vmm.s.HCPhysCoreCode, cbCoreCode);
    248         if (rc == VERR_PGM_MAPPINGS_FIX_CONFLICT)
    249         {
    250             /* try more allocations. */
    251             struct
    252             {
    253                 RTR0PTR  pvR0;
    254                 void    *pvR3;
    255                 RTHCPHYS HCPhys;
    256             } aBadTries[16];
    257             unsigned i = 0;
    258             do
    259             {
    260                 aBadTries[i].pvR3 = pVM->vmm.s.pvHCCoreCodeR3;
    261                 aBadTries[i].pvR0 = pVM->vmm.s.pvHCCoreCodeR0;
    262                 aBadTries[i].HCPhys = pVM->vmm.s.HCPhysCoreCode;
    263                 i++;
    264                 pVM->vmm.s.pvHCCoreCodeR0 = NIL_RTR0PTR;
    265                 pVM->vmm.s.HCPhysCoreCode = NIL_RTHCPHYS;
    266                 pVM->vmm.s.pvHCCoreCodeR3 = SUPContAlloc2(pVM->vmm.s.cbCoreCode, &pVM->vmm.s.pvHCCoreCodeR0, &pVM->vmm.s.HCPhysCoreCode);
    267                 if (!pVM->vmm.s.pvHCCoreCodeR3)
    268                     break;
    269                 rc = PGMR3MapIntermediate(pVM, pVM->vmm.s.pvHCCoreCodeR0, pVM->vmm.s.HCPhysCoreCode, cbCoreCode);
    270             } while (   rc == VERR_PGM_MAPPINGS_FIX_CONFLICT
    271                      && i < ELEMENTS(aBadTries) - 1);
    272 
    273             /* cleanup */
    274             if (VBOX_FAILURE(rc))
    275             {
    276                 aBadTries[i].pvR3 = pVM->vmm.s.pvHCCoreCodeR3;
    277                 aBadTries[i].pvR0 = pVM->vmm.s.pvHCCoreCodeR0;
    278                 aBadTries[i].HCPhys = pVM->vmm.s.HCPhysCoreCode;
    279                 i++;
    280                 LogRel(("Failed to allocated and map core code: rc=%Vrc\n", rc));
    281             }
    282             while (i-- > 0)
    283             {
    284                 LogRel(("Core code alloc attempt #%d: pvR3=%p pvR0=%p HCPhys=%VHp\n",
    285                         i, aBadTries[i].pvR3, aBadTries[i].pvR0, aBadTries[i].HCPhys));
    286                 SUPContFree(aBadTries[i].pvR3);
    287             }
    288         }
    289     }
    290     if (VBOX_SUCCESS(rc))
    291     {
    292         /*
    293          * copy the code.
    294          */
    295         for (unsigned iSwitcher = 0; iSwitcher < ELEMENTS(s_apSwitchers); iSwitcher++)
    296         {
    297             PVMMSWITCHERDEF pSwitcher = s_apSwitchers[iSwitcher];
    298             if (pSwitcher)
    299                 memcpy((uint8_t *)pVM->vmm.s.pvHCCoreCodeR3 + pVM->vmm.s.aoffSwitchers[iSwitcher],
    300                        pSwitcher->pvCode, pSwitcher->cbCode);
    301         }
    302 
    303         /*
    304          * Map the code into the GC address space.
    305          */
    306         rc = MMR3HyperMapHCPhys(pVM, pVM->vmm.s.pvHCCoreCodeR3, pVM->vmm.s.HCPhysCoreCode, cbCoreCode, "Core Code", &pVM->vmm.s.pvGCCoreCode);
    307         if (VBOX_SUCCESS(rc))
    308         {
    309             MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
    310             LogRel(("CoreCode: R3=%VHv R0=%VHv GC=%VGv Phys=%VHp cb=%#x\n",
    311                     pVM->vmm.s.pvHCCoreCodeR3, pVM->vmm.s.pvHCCoreCodeR0, pVM->vmm.s.pvGCCoreCode, pVM->vmm.s.HCPhysCoreCode, pVM->vmm.s.cbCoreCode));
    312 
    313             /*
    314              * Finally, PGM probably have selected a switcher already but we need
    315              * to do get the addresses so we'll reselect it.
    316              * This may legally fail so, we're ignoring the rc.
    317              */
    318             VMMR3SelectSwitcher(pVM, pVM->vmm.s.enmSwitcher);
    319             return rc;
    320         }
    321 
    322         /* shit */
    323         AssertMsgFailed(("PGMR3Map(,%VGv, %VGp, %#x, 0) failed with rc=%Vrc\n", pVM->vmm.s.pvGCCoreCode, pVM->vmm.s.HCPhysCoreCode, cbCoreCode, rc));
    324         SUPContFree(pVM->vmm.s.pvHCCoreCodeR3);
    325     }
    326     else
    327         VMSetError(pVM, rc, RT_SRC_POS,
    328                    N_("Failed to allocate %d bytes of contiguous memory for the world switcher code."),
    329                    cbCoreCode);
    330 
    331     pVM->vmm.s.pvHCCoreCodeR3 = NULL;
    332     pVM->vmm.s.pvHCCoreCodeR0 = NIL_RTR0PTR;
    333     pVM->vmm.s.pvGCCoreCode = 0;
    334     return rc;
    335 }
    336 
    337 
    338 /**
    339  * Initializes the VMM.
    340  *
    341  * @returns VBox status code.
    342  * @param   pVM         The VM to operate on.
    343  */
    344 VMMR3DECL(int) VMMR3Init(PVM pVM)
    345 {
    346     LogFlow(("VMMR3Init\n"));
    347 
    348     /*
    349      * Assert alignment, sizes and order.
    350      */
    351     AssertMsg(pVM->vmm.s.offVM == 0, ("Already initialized!\n"));
    352     AssertMsg(sizeof(pVM->vmm.padding) >= sizeof(pVM->vmm.s),
    353               ("pVM->vmm.padding is too small! vmm.padding %d while vmm.s is %d\n",
    354                sizeof(pVM->vmm.padding), sizeof(pVM->vmm.s)));
    355 
    356     /*
    357      * Init basic VM VMM members.
    358      */
    359     pVM->vmm.s.offVM = RT_OFFSETOF(VM, vmm);
    360     int rc = CFGMR3QueryU32(CFGMR3GetRoot(pVM), "YieldEMTInterval", &pVM->vmm.s.cYieldEveryMillies);
    361     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    362         pVM->vmm.s.cYieldEveryMillies = 23; /* Value arrived at after experimenting with the grub boot prompt. */
    363         //pVM->vmm.s.cYieldEveryMillies = 8; //debugging
    364     else
    365         AssertMsgRCReturn(rc, ("Configuration error. Failed to query \"YieldEMTInterval\", rc=%Vrc\n", rc), rc);
    366 
    367     /* GC switchers are enabled by default. Turned off by HWACCM. */
    368     pVM->vmm.s.fSwitcherDisabled = false;
    369 
    370     /*
    371      * Register the saved state data unit.
    372      */
    373     rc = SSMR3RegisterInternal(pVM, "vmm", 1, VMM_SAVED_STATE_VERSION, VMM_STACK_SIZE + sizeof(RTGCPTR),
    374                                NULL, vmmR3Save, NULL,
    375                                NULL, vmmR3Load, NULL);
    376     if (VBOX_FAILURE(rc))
    377         return rc;
    378 
    379 #ifdef VBOX_WITHOUT_IDT_PATCHING
    380     /*
    381      * Register the Ring-0 VM handle with the session for fast ioctl calls.
    382      */
    383     rc = SUPSetVMForFastIOCtl(pVM->pVMR0);
    384     if (VBOX_FAILURE(rc))
    385         return rc;
    386 #endif
    387 
    388     /*
    389      * Init core code.
    390      */
    391     rc = vmmR3InitCoreCode(pVM);
    392     if (VBOX_SUCCESS(rc))
    393     {
    394         /*
    395          * Allocate & init VMM GC stack.
    396          * The stack pages are also used by the VMM R0 when VMMR0CallHost is invoked.
    397          * (The page protection is modifed during R3 init completion.)
    398          */
    399 #ifdef VBOX_STRICT_VMM_STACK
    400         rc = MMHyperAlloc(pVM, VMM_STACK_SIZE + PAGE_SIZE + PAGE_SIZE, PAGE_SIZE, MM_TAG_VMM, (void **)&pVM->vmm.s.pbHCStack);
    401 #else
    402         rc = MMHyperAlloc(pVM, VMM_STACK_SIZE, PAGE_SIZE, MM_TAG_VMM, (void **)&pVM->vmm.s.pbHCStack);
    403 #endif
    404         if (VBOX_SUCCESS(rc))
    405         {
    406             /* Set HC and GC stack pointers to top of stack. */
    407             pVM->vmm.s.CallHostR0JmpBuf.pvSavedStack = (RTR0PTR)pVM->vmm.s.pbHCStack;
    408             pVM->vmm.s.pbGCStack = MMHyperHC2GC(pVM, pVM->vmm.s.pbHCStack);
    409             pVM->vmm.s.pbGCStackBottom = pVM->vmm.s.pbGCStack + VMM_STACK_SIZE;
    410             AssertRelease(pVM->vmm.s.pbGCStack);
    411 
    412             /* Set hypervisor eip. */
    413             CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStack);
    414 
    415             /*
    416              * Allocate GC & R0 Logger instances (they are finalized in the relocator).
    417              */
    418 #ifdef LOG_ENABLED
    419             PRTLOGGER pLogger = RTLogDefaultInstance();
    420             if (pLogger)
    421             {
    422                 pVM->vmm.s.cbLoggerGC = RT_OFFSETOF(RTLOGGERGC, afGroups[pLogger->cGroups]);
    423                 rc = MMHyperAlloc(pVM, pVM->vmm.s.cbLoggerGC, 0, MM_TAG_VMM, (void **)&pVM->vmm.s.pLoggerHC);
    424                 if (VBOX_SUCCESS(rc))
    425                 {
    426                     pVM->vmm.s.pLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pLoggerHC);
    427 
    428 /*
    429  * Ring-0 logging isn't 100% safe yet (thread id reuse / process exit cleanup), so
    430  * you have to sign up here by adding your defined(DEBUG_<userid>) to the #if.
    431  *
    432  * If you want to log in non-debug modes, you'll have to remember to change SUPDRvShared.c
    433  * to not stub all the log functions.
    434  */
    435 # ifdef DEBUG_sandervl
    436                     rc = MMHyperAlloc(pVM, RT_OFFSETOF(VMMR0LOGGER, Logger.afGroups[pLogger->cGroups]),
    437                                       0, MM_TAG_VMM, (void **)&pVM->vmm.s.pR0Logger);
    438                     if (VBOX_SUCCESS(rc))
    439                     {
    440                         pVM->vmm.s.pR0Logger->pVM = pVM;
    441                         //pVM->vmm.s.pR0Logger->fCreated = false;
    442                         pVM->vmm.s.pR0Logger->cbLogger = RT_OFFSETOF(RTLOGGER, afGroups[pLogger->cGroups]);
    443                     }
    444 # endif
    445                 }
    446             }
    447 #endif /* LOG_ENABLED */
    448 
    449 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    450             /*
    451              * Allocate GC Release Logger instances (finalized in the relocator).
    452              */
    453             if (VBOX_SUCCESS(rc))
    454             {
    455                 PRTLOGGER pRelLogger = RTLogRelDefaultInstance();
    456                 if (pRelLogger)
    457                 {
    458                     pVM->vmm.s.cbRelLoggerGC = RT_OFFSETOF(RTLOGGERGC, afGroups[pRelLogger->cGroups]);
    459                     rc = MMHyperAlloc(pVM, pVM->vmm.s.cbRelLoggerGC, 0, MM_TAG_VMM, (void **)&pVM->vmm.s.pRelLoggerHC);
    460                     if (VBOX_SUCCESS(rc))
    461                         pVM->vmm.s.pRelLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pRelLoggerHC);
    462                 }
    463             }
    464 #endif /* VBOX_WITH_GC_AND_R0_RELEASE_LOG */
    465 
    466 #ifdef VBOX_WITH_NMI
    467             /*
    468              * Allocate mapping for the host APIC.
    469              */
    470             if (VBOX_SUCCESS(rc))
    471             {
    472                 rc = MMR3HyperReserve(pVM, PAGE_SIZE, "Host APIC", &pVM->vmm.s.GCPtrApicBase);
    473                 AssertRC(rc);
    474             }
    475 #endif
    476             if (VBOX_SUCCESS(rc))
    477             {
    478                 rc = RTCritSectInit(&pVM->vmm.s.CritSectVMLock);
    479                 if (VBOX_SUCCESS(rc))
    480                 {
    481                     /*
    482                      * Statistics.
    483                      */
    484                     STAM_REG(pVM, &pVM->vmm.s.StatRunGC,                    STAMTYPE_COUNTER, "/VMM/RunGC",                     STAMUNIT_OCCURENCES, "Number of context switches.");
    485                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetNormal,              STAMTYPE_COUNTER, "/VMM/GCRet/Normal",              STAMUNIT_OCCURENCES, "Number of VINF_SUCCESS returns.");
    486                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetInterrupt,           STAMTYPE_COUNTER, "/VMM/GCRet/Interrupt",           STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT returns.");
    487                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetInterruptHyper,      STAMTYPE_COUNTER, "/VMM/GCRet/InterruptHyper",      STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT_HYPER returns.");
    488                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetGuestTrap,           STAMTYPE_COUNTER, "/VMM/GCRet/GuestTrap",           STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_GUEST_TRAP returns.");
    489                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetRingSwitch,          STAMTYPE_COUNTER, "/VMM/GCRet/RingSwitch",          STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_RING_SWITCH returns.");
    490                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetRingSwitchInt,       STAMTYPE_COUNTER, "/VMM/GCRet/RingSwitchInt",       STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_RING_SWITCH_INT returns.");
    491                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetExceptionPrivilege,  STAMTYPE_COUNTER, "/VMM/GCRet/ExceptionPrivilege",  STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_EXCEPTION_PRIVILEGED returns.");
    492                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetStaleSelector,       STAMTYPE_COUNTER, "/VMM/GCRet/StaleSelector",       STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_STALE_SELECTOR returns.");
    493                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetIRETTrap,            STAMTYPE_COUNTER, "/VMM/GCRet/IRETTrap",            STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_IRET_TRAP returns.");
    494                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetEmulate,             STAMTYPE_COUNTER, "/VMM/GCRet/Emulate",             STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION returns.");
    495                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPatchEmulate,        STAMTYPE_COUNTER, "/VMM/GCRet/PatchEmulate",        STAMUNIT_OCCURENCES, "Number of VINF_PATCH_EMULATE_INSTR returns.");
    496                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetIORead,              STAMTYPE_COUNTER, "/VMM/GCRet/IORead",              STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_IOPORT_READ returns.");
    497                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetIOWrite,             STAMTYPE_COUNTER, "/VMM/GCRet/IOWrite",             STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_IOPORT_WRITE returns.");
    498                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetIOReadWrite,         STAMTYPE_COUNTER, "/VMM/GCRet/IOReadWrite",         STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_IOPORT_READWRITE returns.");
    499                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMMIORead,            STAMTYPE_COUNTER, "/VMM/GCRet/MMIORead",            STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_READ returns.");
    500                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMMIOWrite,           STAMTYPE_COUNTER, "/VMM/GCRet/MMIOWrite",           STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_WRITE returns.");
    501                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMMIOReadWrite,       STAMTYPE_COUNTER, "/VMM/GCRet/MMIOReadWrite",       STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_READ_WRITE returns.");
    502                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMMIOPatchRead,       STAMTYPE_COUNTER, "/VMM/GCRet/MMIOPatchRead",       STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_PATCH_READ returns.");
    503                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMMIOPatchWrite,      STAMTYPE_COUNTER, "/VMM/GCRet/MMIOPatchWrite",      STAMUNIT_OCCURENCES, "Number of VINF_IOM_HC_MMIO_PATCH_WRITE returns.");
    504                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetLDTFault,            STAMTYPE_COUNTER, "/VMM/GCRet/LDTFault",            STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_GDT_FAULT returns.");
    505                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetGDTFault,            STAMTYPE_COUNTER, "/VMM/GCRet/GDTFault",            STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_LDT_FAULT returns.");
    506                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetIDTFault,            STAMTYPE_COUNTER, "/VMM/GCRet/IDTFault",            STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_IDT_FAULT returns.");
    507                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetTSSFault,            STAMTYPE_COUNTER, "/VMM/GCRet/TSSFault",            STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_TSS_FAULT returns.");
    508                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPDFault,             STAMTYPE_COUNTER, "/VMM/GCRet/PDFault",             STAMUNIT_OCCURENCES, "Number of VINF_EM_EXECUTE_INSTRUCTION_PD_FAULT returns.");
    509                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetCSAMTask,            STAMTYPE_COUNTER, "/VMM/GCRet/CSAMTask",            STAMUNIT_OCCURENCES, "Number of VINF_CSAM_PENDING_ACTION returns.");
    510                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetSyncCR3,             STAMTYPE_COUNTER, "/VMM/GCRet/SyncCR",              STAMUNIT_OCCURENCES, "Number of VINF_PGM_SYNC_CR3 returns.");
    511                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetMisc,                STAMTYPE_COUNTER, "/VMM/GCRet/Misc",                STAMUNIT_OCCURENCES, "Number of misc returns.");
    512                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPatchInt3,           STAMTYPE_COUNTER, "/VMM/GCRet/PatchInt3",           STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_INT3 returns.");
    513                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPatchPF,             STAMTYPE_COUNTER, "/VMM/GCRet/PatchPF",             STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_TRAP_PF returns.");
    514                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPatchGP,             STAMTYPE_COUNTER, "/VMM/GCRet/PatchGP",             STAMUNIT_OCCURENCES, "Number of VINF_PATM_PATCH_TRAP_GP returns.");
    515                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPatchIretIRQ,        STAMTYPE_COUNTER, "/VMM/GCRet/PatchIret",           STAMUNIT_OCCURENCES, "Number of VINF_PATM_PENDING_IRQ_AFTER_IRET returns.");
    516                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPageOverflow,        STAMTYPE_COUNTER, "/VMM/GCRet/InvlpgOverflow",      STAMUNIT_OCCURENCES, "Number of VERR_REM_FLUSHED_PAGES_OVERFLOW returns.");
    517                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetRescheduleREM,       STAMTYPE_COUNTER, "/VMM/GCRet/ScheduleREM",         STAMUNIT_OCCURENCES, "Number of VINF_EM_RESCHEDULE_REM returns.");
    518                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetToR3,                STAMTYPE_COUNTER, "/VMM/GCRet/ToR3",                STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TO_R3 returns.");
    519                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetTimerPending,        STAMTYPE_COUNTER, "/VMM/GCRet/TimerPending",        STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_TIMER_PENDING returns.");
    520                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetInterruptPending,    STAMTYPE_COUNTER, "/VMM/GCRet/InterruptPending",    STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_INTERRUPT_PENDING returns.");
    521                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetCallHost,            STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/Misc",       STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    522                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPGMGrowRAM,          STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/GrowRAM",    STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    523                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPDMLock,             STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/PDMLock",    STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    524                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetLogFlush,            STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/LogFlush",   STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    525                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPDMQueueFlush,       STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/QueueFlush", STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    526                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPGMPoolGrow,         STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/PGMPoolGrow",STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    527                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetRemReplay,           STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/REMReplay",  STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    528                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetVMSetError,          STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/VMSetError", STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    529                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPGMLock,             STAMTYPE_COUNTER, "/VMM/GCRet/CallHost/PGMLock",    STAMUNIT_OCCURENCES, "Number of VINF_VMM_CALL_HOST returns.");
    530                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPATMDuplicateFn,     STAMTYPE_COUNTER, "/VMM/GCRet/PATMDuplicateFn",     STAMUNIT_OCCURENCES, "Number of VINF_PATM_DUPLICATE_FUNCTION returns.");
    531                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPGMChangeMode,       STAMTYPE_COUNTER, "/VMM/GCRet/PGMChangeMode",       STAMUNIT_OCCURENCES, "Number of VINF_PGM_CHANGE_MODE returns.");
    532                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetEmulHlt,             STAMTYPE_COUNTER, "/VMM/GCRet/EmulHlt",             STAMUNIT_OCCURENCES, "Number of VINF_EM_RAW_EMULATE_INSTR_HLT returns.");
    533                     STAM_REG(pVM, &pVM->vmm.s.StatGCRetPendingRequest,      STAMTYPE_COUNTER, "/VMM/GCRet/PendingRequest",      STAMUNIT_OCCURENCES, "Number of VINF_EM_PENDING_REQUEST returns.");
    534 
    535                     return VINF_SUCCESS;
    536                 }
    537                 AssertRC(rc);
    538             }
    539         }
    540         /** @todo: Need failure cleanup. */
    541 
    542         //more todo in here?
    543         //if (VBOX_SUCCESS(rc))
    544         //{
    545         //}
    546         //int rc2 = vmmR3TermCoreCode(pVM);
    547         //AssertRC(rc2));
    548     }
    549 
    550     return rc;
    551 }
    552 
    553 
    554 /**
    555  * Ring-3 init finalizing.
    556  *
    557  * @returns VBox status code.
    558  * @param   pVM         The VM handle.
    559  */
    560 VMMR3DECL(int) VMMR3InitFinalize(PVM pVM)
    561 {
    562 #ifdef VBOX_STRICT_VMM_STACK
    563     /*
    564      * Two inaccessible pages at each sides of the stack to catch over/under-flows.
    565      */
    566     memset(pVM->vmm.s.pbHCStack - PAGE_SIZE, 0xcc, PAGE_SIZE);
    567     PGMMapSetPage(pVM, MMHyperHC2GC(pVM, pVM->vmm.s.pbHCStack - PAGE_SIZE), PAGE_SIZE, 0);
    568     RTMemProtect(pVM->vmm.s.pbHCStack - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
    569 
    570     memset(pVM->vmm.s.pbHCStack + VMM_STACK_SIZE, 0xcc, PAGE_SIZE);
    571     PGMMapSetPage(pVM, MMHyperHC2GC(pVM, pVM->vmm.s.pbHCStack + VMM_STACK_SIZE), PAGE_SIZE, 0);
    572     RTMemProtect(pVM->vmm.s.pbHCStack + VMM_STACK_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
    573 #endif
    574 
    575     /*
    576      * Set page attributes to r/w for stack pages.
    577      */
    578     int rc = PGMMapSetPage(pVM, pVM->vmm.s.pbGCStack, VMM_STACK_SIZE, X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
    579     AssertRC(rc);
    580     if (VBOX_SUCCESS(rc))
    581     {
    582         /*
    583          * Create the EMT yield timer.
    584          */
    585         rc = TMR3TimerCreateInternal(pVM, TMCLOCK_REAL, vmmR3YieldEMT, NULL, "EMT Yielder", &pVM->vmm.s.pYieldTimer);
    586         if (VBOX_SUCCESS(rc))
    587            rc = TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldEveryMillies);
    588     }
    589 #ifdef VBOX_WITH_NMI
    590     /*
    591      * Map the host APIC into GC - This may be host os specific!
    592      */
    593     if (VBOX_SUCCESS(rc))
    594         rc = PGMMap(pVM, pVM->vmm.s.GCPtrApicBase, 0xfee00000, PAGE_SIZE,
    595                     X86_PTE_P | X86_PTE_RW | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_A | X86_PTE_D);
    596 #endif
    597     return rc;
    598 }
    599 
    600 
    601 /**
    602  * Initializes the R0 VMM.
    603  *
    604  * @returns VBox status code.
    605  * @param   pVM         The VM to operate on.
    606  */
    607 VMMR3DECL(int) VMMR3InitR0(PVM pVM)
    608 {
    609     int rc;
    610 
    611     /*
    612      * Initialize the ring-0 logger if we haven't done so yet.
    613      */
    614     if (    pVM->vmm.s.pR0Logger
    615         &&  !pVM->vmm.s.pR0Logger->fCreated)
    616     {
    617         rc = VMMR3UpdateLoggers(pVM);
    618         if (VBOX_FAILURE(rc))
    619             return rc;
    620     }
    621 
    622     /*
    623      * Call Ring-0 entry with init code.
    624      */
    625     for (;;)
    626     {
    627 #ifdef NO_SUPCALLR0VMM
    628         //rc = VERR_GENERAL_FAILURE;
    629         rc = VINF_SUCCESS;
    630 #else
    631         rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_VMMR0_INIT, (void *)VBOX_VERSION);
    632 #endif
    633         if (    pVM->vmm.s.pR0Logger
    634             &&  pVM->vmm.s.pR0Logger->Logger.offScratch > 0)
    635             RTLogFlushToLogger(&pVM->vmm.s.pR0Logger->Logger, NULL);
    636         if (rc != VINF_VMM_CALL_HOST)
    637             break;
    638         rc = vmmR3ServiceCallHostRequest(pVM);
    639         if (VBOX_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
    640             break;
    641         break; // remove this when we do setjmp for all ring-0 stuff.
    642     }
    643 
    644     if (VBOX_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
    645     {
    646         LogRel(("R0 init failed, rc=%Vra\n", rc));
    647         if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
    648             rc = VERR_INTERNAL_ERROR;
    649     }
    650     return rc;
    651 }
    652 
    653 
    654 /**
    655  * Initializes the GC VMM.
    656  *
    657  * @returns VBox status code.
    658  * @param   pVM         The VM to operate on.
    659  */
    660 VMMR3DECL(int) VMMR3InitGC(PVM pVM)
    661 {
    662     /* In VMX mode, there's no need to init GC. */
    663     if (pVM->vmm.s.fSwitcherDisabled)
    664         return VINF_SUCCESS;
    665 
    666     /*
    667      * Call VMMGCInit():
    668      *      -# resolve the address.
    669      *      -# setup stackframe and EIP to use the trampoline.
    670      *      -# do a generic hypervisor call.
    671      */
    672     RTGCPTR GCPtrEP;
    673     int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "VMMGCEntry", &GCPtrEP);
    674     if (VBOX_SUCCESS(rc))
    675     {
    676         CPUMHyperSetCtxCore(pVM, NULL);
    677         CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom); /* Clear the stack. */
    678         CPUMPushHyper(pVM, VBOX_VERSION);               /* Param 2: Version argument. */
    679         CPUMPushHyper(pVM, VMMGC_DO_VMMGC_INIT);        /* Param 1: Operation. */
    680         CPUMPushHyper(pVM, pVM->pVMGC);                 /* Param 0: pVM */
    681         CPUMPushHyper(pVM, 3 * sizeof(RTGCPTR));        /* trampoline param: stacksize.  */
    682         CPUMPushHyper(pVM, GCPtrEP);                    /* Call EIP. */
    683         CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    684 
    685         for (;;)
    686         {
    687 #ifdef NO_SUPCALLR0VMM
    688             //rc = VERR_GENERAL_FAILURE;
    689             rc = VINF_SUCCESS;
    690 #else
    691             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_CALL_HYPERVISOR, NULL);
    692 #endif
    693 #ifdef LOG_ENABLED
    694             PRTLOGGERGC pLogger = pVM->vmm.s.pLoggerHC;
    695             if (    pLogger
    696                 &&  pLogger->offScratch > 0)
    697                 RTLogFlushGC(NULL, pLogger);
    698 #endif
    699 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    700             PRTLOGGERGC pRelLogger = pVM->vmm.s.pRelLoggerHC;
    701             if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
    702                 RTLogFlushGC(RTLogRelDefaultInstance(), pRelLogger);
    703 #endif
    704             if (rc != VINF_VMM_CALL_HOST)
    705                 break;
    706             rc = vmmR3ServiceCallHostRequest(pVM);
    707             if (VBOX_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
    708                 break;
    709         }
    710 
    711         if (VBOX_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
    712         {
    713             VMMR3FatalDump(pVM, rc);
    714             if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
    715                 rc = VERR_INTERNAL_ERROR;
    716         }
    717         AssertRC(rc);
    718     }
    719     return rc;
    720 }
    721 
    722 
    723 /**
    724  * Terminate the VMM bits.
    725  *
    726  * @returns VINF_SUCCESS.
    727  * @param   pVM         The VM handle.
    728  */
    729 VMMR3DECL(int) VMMR3Term(PVM pVM)
    730 {
    731     /** @todo must call ring-0 so the logger thread instance can be properly removed. */
    732 
    733 #ifdef VBOX_STRICT_VMM_STACK
    734     /*
    735      * Make the two stack guard pages present again.
    736      */
    737     RTMemProtect(pVM->vmm.s.pbHCStack - PAGE_SIZE,      PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
    738     RTMemProtect(pVM->vmm.s.pbHCStack + VMM_STACK_SIZE, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
    739 #endif
    740     return VINF_SUCCESS;
    741 }
    742 
    743 
    744 /**
    745  * Applies relocations to data and code managed by this
    746  * component. This function will be called at init and
    747  * whenever the VMM need to relocate it self inside the GC.
    748  *
    749  * The VMM will need to apply relocations to the core code.
    750  *
    751  * @param   pVM         The VM handle.
    752  * @param   offDelta    The relocation delta.
    753  */
    754 VMMR3DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
    755 {
    756     LogFlow(("VMMR3Relocate: offDelta=%VGv\n", offDelta));
    757 
    758     /*
    759      * Recalc the GC address.
    760      */
    761     pVM->vmm.s.pvGCCoreCode = MMHyperHC2GC(pVM, pVM->vmm.s.pvHCCoreCodeR3);
    762 
    763     /*
    764      * The stack.
    765      */
    766     CPUMSetHyperESP(pVM, CPUMGetHyperESP(pVM) + offDelta);
    767     pVM->vmm.s.pbGCStack = MMHyperHC2GC(pVM, pVM->vmm.s.pbHCStack);
    768     pVM->vmm.s.pbGCStackBottom = pVM->vmm.s.pbGCStack + VMM_STACK_SIZE;
    769 
    770     /*
    771      * All the switchers.
    772      */
    773     for (unsigned iSwitcher = 0; iSwitcher < ELEMENTS(s_apSwitchers); iSwitcher++)
    774     {
    775         PVMMSWITCHERDEF pSwitcher = s_apSwitchers[iSwitcher];
    776         if (pSwitcher && pSwitcher->pfnRelocate)
    777         {
    778             unsigned off = pVM->vmm.s.aoffSwitchers[iSwitcher];
    779             pSwitcher->pfnRelocate(pVM,
    780                                    pSwitcher,
    781                                    (uint8_t *)pVM->vmm.s.pvHCCoreCodeR0 + off,
    782                                    (uint8_t *)pVM->vmm.s.pvHCCoreCodeR3 + off,
    783                                    pVM->vmm.s.pvGCCoreCode + off,
    784                                    pVM->vmm.s.HCPhysCoreCode + off);
    785         }
    786     }
    787 
    788     /*
    789      * Recalc the GC address for the current switcher.
    790      */
    791     PVMMSWITCHERDEF pSwitcher   = s_apSwitchers[pVM->vmm.s.enmSwitcher];
    792     RTGCPTR         GCPtr       = pVM->vmm.s.pvGCCoreCode + pVM->vmm.s.aoffSwitchers[pVM->vmm.s.enmSwitcher];
    793     pVM->vmm.s.pfnGCGuestToHost         = GCPtr + pSwitcher->offGCGuestToHost;
    794     pVM->vmm.s.pfnGCCallTrampoline      = GCPtr + pSwitcher->offGCCallTrampoline;
    795     pVM->pfnVMMGCGuestToHostAsm         = GCPtr + pSwitcher->offGCGuestToHostAsm;
    796     pVM->pfnVMMGCGuestToHostAsmHyperCtx = GCPtr + pSwitcher->offGCGuestToHostAsmHyperCtx;
    797     pVM->pfnVMMGCGuestToHostAsmGuestCtx = GCPtr + pSwitcher->offGCGuestToHostAsmGuestCtx;
    798 
    799     /*
    800      * Get other GC entry points.
    801      */
    802     int rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "CPUMGCResumeGuest", &pVM->vmm.s.pfnCPUMGCResumeGuest);
    803     AssertReleaseMsgRC(rc, ("CPUMGCResumeGuest not found! rc=%Vra\n", rc));
    804 
    805     rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "CPUMGCResumeGuestV86", &pVM->vmm.s.pfnCPUMGCResumeGuestV86);
    806     AssertReleaseMsgRC(rc, ("CPUMGCResumeGuestV86 not found! rc=%Vra\n", rc));
    807 
    808     /*
    809      * Update the logger.
    810      */
    811     VMMR3UpdateLoggers(pVM);
    812 }
    813 
    814 
    815 /**
    816  * Updates the settings for the GC and R0 loggers.
    817  *
    818  * @returns VBox status code.
    819  * @param   pVM     The VM handle.
    820  */
    821 VMMR3DECL(int)  VMMR3UpdateLoggers(PVM pVM)
    822 {
    823     /*
    824      * Simply clone the logger instance (for GC).
    825      */
    826     int rc = VINF_SUCCESS;
    827     RTGCPTR GCPtrLoggerFlush = 0;
    828 
    829     if (pVM->vmm.s.pLoggerHC
    830 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    831         || pVM->vmm.s.pRelLoggerHC
    832 #endif
    833        )
    834     {
    835         rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "vmmGCLoggerFlush", &GCPtrLoggerFlush);
    836         AssertReleaseMsgRC(rc, ("vmmGCLoggerFlush not found! rc=%Vra\n", rc));
    837     }
    838 
    839     if (pVM->vmm.s.pLoggerHC)
    840     {
    841         RTGCPTR GCPtrLoggerWrapper = 0;
    842         rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "vmmGCLoggerWrapper", &GCPtrLoggerWrapper);
    843         AssertReleaseMsgRC(rc, ("vmmGCLoggerWrapper not found! rc=%Vra\n", rc));
    844         pVM->vmm.s.pLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pLoggerHC);
    845         rc = RTLogCloneGC(NULL /* default */, pVM->vmm.s.pLoggerHC, pVM->vmm.s.cbLoggerGC,
    846                           GCPtrLoggerWrapper,  GCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
    847         AssertReleaseMsgRC(rc, ("RTLogCloneGC failed! rc=%Vra\n", rc));
    848     }
    849 
    850 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    851     if (pVM->vmm.s.pRelLoggerHC)
    852     {
    853         RTGCPTR GCPtrLoggerWrapper = 0;
    854         rc = PDMR3GetSymbolGC(pVM, VMMGC_MAIN_MODULE_NAME, "vmmGCRelLoggerWrapper", &GCPtrLoggerWrapper);
    855         AssertReleaseMsgRC(rc, ("vmmGCRelLoggerWrapper not found! rc=%Vra\n", rc));
    856         pVM->vmm.s.pRelLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pRelLoggerHC);
    857         rc = RTLogCloneGC(RTLogRelDefaultInstance(), pVM->vmm.s.pRelLoggerHC, pVM->vmm.s.cbRelLoggerGC,
    858                           GCPtrLoggerWrapper,  GCPtrLoggerFlush, RTLOGFLAGS_BUFFERED);
    859         AssertReleaseMsgRC(rc, ("RTLogCloneGC failed! rc=%Vra\n", rc));
    860     }
    861 #endif /* VBOX_WITH_GC_AND_R0_RELEASE_LOG */
    862 
    863     /*
    864      * For the ring-0 EMT logger, we use a per-thread logger
    865      * instance in ring-0. Only initialize it once.
    866      */
    867     PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0Logger;
    868     if (pR0Logger)
    869     {
    870         if (!pR0Logger->fCreated)
    871         {
    872             RTHCPTR pfnLoggerWrapper = NULL;
    873             rc = PDMR3GetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerWrapper", &pfnLoggerWrapper);
    874             AssertReleaseMsgRCReturn(rc, ("VMMLoggerWrapper not found! rc=%Vra\n", rc), rc);
    875 
    876             RTHCPTR pfnLoggerFlush = NULL;
    877             rc = PDMR3GetSymbolR0(pVM, VMMR0_MAIN_MODULE_NAME, "vmmR0LoggerFlush", &pfnLoggerFlush);
    878             AssertReleaseMsgRCReturn(rc, ("VMMLoggerFlush not found! rc=%Vra\n", rc), rc);
    879 
    880             rc = RTLogCreateForR0(&pR0Logger->Logger, pR0Logger->cbLogger,
    881                                   *(PFNRTLOGGER *)&pfnLoggerWrapper, *(PFNRTLOGFLUSH *)&pfnLoggerFlush,
    882                                   RTLOGFLAGS_BUFFERED, RTLOGDEST_DUMMY);
    883             AssertReleaseMsgRCReturn(rc, ("RTLogCloneGC failed! rc=%Vra\n", rc), rc);
    884             pR0Logger->fCreated = true;
    885         }
    886 
    887         rc = RTLogCopyGroupsAndFlags(&pR0Logger->Logger, NULL /* default */, RTLOGFLAGS_BUFFERED, 0);
    888         AssertRC(rc);
    889     }
    890 
    891     return rc;
    892 }
    893 
    894 
    895 /**
    896  * Generic switch code relocator.
    897  *
    898  * @param   pVM         The VM handle.
    899  * @param   pSwitcher   The switcher definition.
    900  * @param   pu8CodeR3   Pointer to the core code block for the switcher, ring-3 mapping.
    901  * @param   pu8CodeR0   Pointer to the core code block for the switcher, ring-0 mapping.
    902  * @param   GCPtrCode   The guest context address corresponding to pu8Code.
    903  * @param   u32IDCode   The identity mapped (ID) address corresponding to pu8Code.
    904  * @param   SelCS       The hypervisor CS selector.
    905  * @param   SelDS       The hypervisor DS selector.
    906  * @param   SelTSS      The hypervisor TSS selector.
    907  * @param   GCPtrGDT    The GC address of the hypervisor GDT.
    908  * @param   SelCS64     The 64-bit mode hypervisor CS selector.
    909  */
    910 static void vmmR3SwitcherGenericRelocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode,
    911                                          RTSEL SelCS, RTSEL SelDS, RTSEL SelTSS, RTGCPTR GCPtrGDT, RTSEL SelCS64)
    912 {
    913     union
    914     {
    915         const uint8_t *pu8;
    916         const uint16_t *pu16;
    917         const uint32_t *pu32;
    918         const uint64_t *pu64;
    919         const void     *pv;
    920         uintptr_t       u;
    921     } u;
    922     u.pv = pSwitcher->pvFixups;
    923 
    924     /*
    925      * Process fixups.
    926      */
    927     uint8_t u8;
    928     while ((u8 = *u.pu8++) != FIX_THE_END)
    929     {
    930         /*
    931          * Get the source (where to write the fixup).
    932          */
    933         uint32_t offSrc = *u.pu32++;
    934         Assert(offSrc < pSwitcher->cbCode);
    935         union
    936         {
    937             uint8_t    *pu8;
    938             uint16_t   *pu16;
    939             uint32_t   *pu32;
    940             uint64_t   *pu64;
    941             uintptr_t   u;
    942         } uSrc;
    943         uSrc.pu8 = pu8CodeR3 + offSrc;
    944 
    945         /* The fixup target and method depends on the type. */
    946         switch (u8)
    947         {
    948             /*
    949              * 32-bit relative, source in HC and target in GC.
    950              */
    951             case FIX_HC_2_GC_NEAR_REL:
    952             {
    953                 Assert(offSrc - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offSrc - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    954                 uint32_t offTrg = *u.pu32++;
    955                 Assert(offTrg - pSwitcher->offGCCode < pSwitcher->cbGCCode);
    956                 *uSrc.pu32 = (uint32_t)((GCPtrCode + offTrg) - (uSrc.u + 4));
    957                 break;
    958             }
    959 
    960             /*
    961              * 32-bit relative, source in HC and target in ID.
    962              */
    963             case FIX_HC_2_ID_NEAR_REL:
    964             {
    965                 Assert(offSrc - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offSrc - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    966                 uint32_t offTrg = *u.pu32++;
    967                 Assert(offTrg - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offTrg - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    968                 *uSrc.pu32 = (uint32_t)((u32IDCode + offTrg) - (uSrc.u + 4));
    969                 break;
    970             }
    971 
    972             /*
    973              * 32-bit relative, source in GC and target in HC.
    974              */
    975             case FIX_GC_2_HC_NEAR_REL:
    976             {
    977                 Assert(offSrc - pSwitcher->offGCCode < pSwitcher->cbGCCode);
    978                 uint32_t offTrg = *u.pu32++;
    979                 Assert(offTrg - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offTrg - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    980                 *uSrc.pu32 = (uint32_t)(((uintptr_t)pu8CodeR0 + offTrg) - (GCPtrCode + offSrc + 4));
    981                 break;
    982             }
    983 
    984             /*
    985              * 32-bit relative, source in GC and target in ID.
    986              */
    987             case FIX_GC_2_ID_NEAR_REL:
    988             {
    989                 Assert(offSrc - pSwitcher->offGCCode < pSwitcher->cbGCCode);
    990                 uint32_t offTrg = *u.pu32++;
    991                 Assert(offTrg - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offTrg - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    992                 *uSrc.pu32 = (uint32_t)((u32IDCode + offTrg) - (GCPtrCode + offSrc + 4));
    993                 break;
    994             }
    995 
    996             /*
    997              * 32-bit relative, source in ID and target in HC.
    998              */
    999             case FIX_ID_2_HC_NEAR_REL:
    1000             {
    1001                 Assert(offSrc - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offSrc - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    1002                 uint32_t offTrg = *u.pu32++;
    1003                 Assert(offTrg - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offTrg - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    1004                 *uSrc.pu32 = (uint32_t)(((uintptr_t)pu8CodeR0 + offTrg) - (u32IDCode + offSrc + 4));
    1005                 break;
    1006             }
    1007 
    1008             /*
    1009              * 32-bit relative, source in ID and target in HC.
    1010              */
    1011             case FIX_ID_2_GC_NEAR_REL:
    1012             {
    1013                 Assert(offSrc - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offSrc - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    1014                 uint32_t offTrg = *u.pu32++;
    1015                 Assert(offTrg - pSwitcher->offGCCode < pSwitcher->cbGCCode);
    1016                 *uSrc.pu32 = (uint32_t)((GCPtrCode + offTrg) - (u32IDCode + offSrc + 4));
    1017                 break;
    1018             }
    1019 
    1020             /*
    1021              * 16:32 far jump, target in GC.
    1022              */
    1023             case FIX_GC_FAR32:
    1024             {
    1025                 uint32_t offTrg = *u.pu32++;
    1026                 Assert(offTrg - pSwitcher->offGCCode < pSwitcher->cbGCCode);
    1027                 *uSrc.pu32++ = (uint32_t)(GCPtrCode + offTrg);
    1028                 *uSrc.pu16++ = SelCS;
    1029                 break;
    1030             }
    1031 
    1032             /*
    1033              * Make 32-bit GC pointer given CPUM offset.
    1034              */
    1035             case FIX_GC_CPUM_OFF:
    1036             {
    1037                 uint32_t offCPUM = *u.pu32++;
    1038                 Assert(offCPUM < sizeof(pVM->cpum));
    1039                 *uSrc.pu32 = (uint32_t)(VM_GUEST_ADDR(pVM, &pVM->cpum) + offCPUM);
    1040                 break;
    1041             }
    1042 
    1043             /*
    1044              * Make 32-bit GC pointer given VM offset.
    1045              */
    1046             case FIX_GC_VM_OFF:
    1047             {
    1048                 uint32_t offVM = *u.pu32++;
    1049                 Assert(offVM < sizeof(VM));
    1050                 *uSrc.pu32 = (uint32_t)(VM_GUEST_ADDR(pVM, pVM) + offVM);
    1051                 break;
    1052             }
    1053 
    1054             /*
    1055              * Make 32-bit HC pointer given CPUM offset.
    1056              */
    1057             case FIX_HC_CPUM_OFF:
    1058             {
    1059                 uint32_t offCPUM = *u.pu32++;
    1060                 Assert(offCPUM < sizeof(pVM->cpum));
    1061                 *uSrc.pu32 = (uint32_t)pVM->pVMR0 + RT_OFFSETOF(VM, cpum) + offCPUM;
    1062                 break;
    1063             }
    1064 
    1065             /*
    1066              * Make 32-bit R0 pointer given VM offset.
    1067              */
    1068             case FIX_HC_VM_OFF:
    1069             {
    1070                 uint32_t offVM = *u.pu32++;
    1071                 Assert(offVM < sizeof(VM));
    1072                 *uSrc.pu32 = (uint32_t)pVM->pVMR0 + offVM;
    1073                 break;
    1074             }
    1075 
    1076             /*
    1077              * Store the 32-Bit CR3 (32-bit) for the intermediate memory context.
    1078              */
    1079             case FIX_INTER_32BIT_CR3:
    1080             {
    1081 
    1082                 *uSrc.pu32 = PGMGetInter32BitCR3(pVM);
    1083                 break;
    1084             }
    1085 
    1086             /*
    1087              * Store the PAE CR3 (32-bit) for the intermediate memory context.
    1088              */
    1089             case FIX_INTER_PAE_CR3:
    1090             {
    1091 
    1092                 *uSrc.pu32 = PGMGetInterPaeCR3(pVM);
    1093                 break;
    1094             }
    1095 
    1096             /*
    1097              * Store the AMD64 CR3 (32-bit) for the intermediate memory context.
    1098              */
    1099             case FIX_INTER_AMD64_CR3:
    1100             {
    1101 
    1102                 *uSrc.pu32 = PGMGetInterAmd64CR3(pVM);
    1103                 break;
    1104             }
    1105 
    1106             /*
    1107              * Store the 32-Bit CR3 (32-bit) for the hypervisor (shadow) memory context.
    1108              */
    1109             case FIX_HYPER_32BIT_CR3:
    1110             {
    1111 
    1112                 *uSrc.pu32 = PGMGetHyper32BitCR3(pVM);
    1113                 break;
    1114             }
    1115 
    1116             /*
    1117              * Store the PAE CR3 (32-bit) for the hypervisor (shadow) memory context.
    1118              */
    1119             case FIX_HYPER_PAE_CR3:
    1120             {
    1121 
    1122                 *uSrc.pu32 = PGMGetHyperPaeCR3(pVM);
    1123                 break;
    1124             }
    1125 
    1126             /*
    1127              * Store the AMD64 CR3 (32-bit) for the hypervisor (shadow) memory context.
    1128              */
    1129             case FIX_HYPER_AMD64_CR3:
    1130             {
    1131 
    1132                 *uSrc.pu32 = PGMGetHyperAmd64CR3(pVM);
    1133                 break;
    1134             }
    1135 
    1136             /*
    1137              * Store Hypervisor CS (16-bit).
    1138              */
    1139             case FIX_HYPER_CS:
    1140             {
    1141                 *uSrc.pu16 = SelCS;
    1142                 break;
    1143             }
    1144 
    1145             /*
    1146              * Store Hypervisor DS (16-bit).
    1147              */
    1148             case FIX_HYPER_DS:
    1149             {
    1150                 *uSrc.pu16 = SelDS;
    1151                 break;
    1152             }
    1153 
    1154             /*
    1155              * Store Hypervisor TSS (16-bit).
    1156              */
    1157             case FIX_HYPER_TSS:
    1158             {
    1159                 *uSrc.pu16 = SelTSS;
    1160                 break;
    1161             }
    1162 
    1163             /*
    1164              * Store the 32-bit GC address of the 2nd dword of the TSS descriptor (in the GDT).
    1165              */
    1166             case FIX_GC_TSS_GDTE_DW2:
    1167             {
    1168                 RTGCPTR GCPtr = GCPtrGDT + (SelTSS & ~7) + 4;
    1169                 *uSrc.pu32 = (uint32_t)GCPtr;
    1170                 break;
    1171             }
    1172 
    1173 
    1174             ///@todo case FIX_CR4_MASK:
    1175             ///@todo case FIX_CR4_OSFSXR:
    1176 
    1177             /*
    1178              * Insert relative jump to specified target it FXSAVE/FXRSTOR isn't supported by the cpu.
    1179              */
    1180             case FIX_NO_FXSAVE_JMP:
    1181             {
    1182                 uint32_t offTrg = *u.pu32++;
    1183                 Assert(offTrg < pSwitcher->cbCode);
    1184                 if (!CPUMSupportsFXSR(pVM))
    1185                 {
    1186                     *uSrc.pu8++ = 0xe9; /* jmp rel32 */
    1187                     *uSrc.pu32++ = offTrg - (offSrc + 5);
    1188                 }
    1189                 else
    1190                 {
    1191                     *uSrc.pu8++ = *((uint8_t *)pSwitcher->pvCode + offSrc);
    1192                     *uSrc.pu32++ = *(uint32_t *)((uint8_t *)pSwitcher->pvCode + offSrc + 1);
    1193                 }
    1194                 break;
    1195             }
    1196 
    1197             /*
    1198              * Insert relative jump to specified target it SYSENTER isn't used by the host.
    1199              */
    1200             case FIX_NO_SYSENTER_JMP:
    1201             {
    1202                 uint32_t offTrg = *u.pu32++;
    1203                 Assert(offTrg < pSwitcher->cbCode);
    1204                 if (!CPUMIsHostUsingSysEnter(pVM))
    1205                 {
    1206                     *uSrc.pu8++ = 0xe9; /* jmp rel32 */
    1207                     *uSrc.pu32++ = offTrg - (offSrc + 5);
    1208                 }
    1209                 else
    1210                 {
    1211                     *uSrc.pu8++ = *((uint8_t *)pSwitcher->pvCode + offSrc);
    1212                     *uSrc.pu32++ = *(uint32_t *)((uint8_t *)pSwitcher->pvCode + offSrc + 1);
    1213                 }
    1214                 break;
    1215             }
    1216 
    1217             /*
    1218              * Insert relative jump to specified target it SYSENTER isn't used by the host.
    1219              */
    1220             case FIX_NO_SYSCALL_JMP:
    1221             {
    1222                 uint32_t offTrg = *u.pu32++;
    1223                 Assert(offTrg < pSwitcher->cbCode);
    1224                 if (!CPUMIsHostUsingSysEnter(pVM))
    1225                 {
    1226                     *uSrc.pu8++ = 0xe9; /* jmp rel32 */
    1227                     *uSrc.pu32++ = offTrg - (offSrc + 5);
    1228                 }
    1229                 else
    1230                 {
    1231                     *uSrc.pu8++ = *((uint8_t *)pSwitcher->pvCode + offSrc);
    1232                     *uSrc.pu32++ = *(uint32_t *)((uint8_t *)pSwitcher->pvCode + offSrc + 1);
    1233                 }
    1234                 break;
    1235             }
    1236 
    1237             /*
    1238              * 32-bit HC pointer fixup to (HC) target within the code (32-bit offset).
    1239              */
    1240             case FIX_HC_32BIT:
    1241             {
    1242                 uint32_t offTrg = *u.pu32++;
    1243                 Assert(offSrc < pSwitcher->cbCode);
    1244                 Assert(offTrg - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offTrg - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    1245                 *uSrc.pu32 = (uintptr_t)pu8CodeR0 + offTrg;
    1246                 break;
    1247             }
    1248 
    1249 #if defined(__AMD64__) || defined(VBOX_WITH_HYBIRD_32BIT_KERNEL)
    1250             /*
    1251              * 64-bit HC pointer fixup to (HC) target within the code (32-bit offset).
    1252              */
    1253             case FIX_HC_64BIT:
    1254             {
    1255                 uint32_t offTrg = *u.pu32++;
    1256                 Assert(offSrc < pSwitcher->cbCode);
    1257                 Assert(offTrg - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0 || offTrg - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1);
    1258                 *uSrc.pu64 = (uintptr_t)pu8CodeR0 + offTrg;
    1259                 break;
    1260             }
    1261 
    1262             /*
    1263              * 64-bit HC Code Selector (no argument).
    1264              */
    1265             case FIX_HC_64BIT_CS:
    1266             {
    1267                 Assert(offSrc < pSwitcher->cbCode);
    1268 #if defined(__DARWIN__) && defined(VBOX_WITH_HYBIRD_32BIT_KERNEL)
    1269                 *uSrc.pu16 = 0x80; /* KERNEL64_CS from i386/seg.h */
    1270 #else
    1271                 AssertFatalMsgFailed(("FIX_HC_64BIT_CS not implemented for this host\n"));
    1272 #endif
    1273                 break;
    1274             }
    1275 
    1276             /*
    1277              * 64-bit HC pointer to the CPUM instance data (no argument).
    1278              */
    1279             case FIX_HC_64BIT_CPUM:
    1280             {
    1281                 Assert(offSrc < pSwitcher->cbCode);
    1282                 *uSrc.pu64 = pVM->pVMR0 + RT_OFFSETOF(VM, cpum);
    1283                 break;
    1284             }
    1285 #endif
    1286 
    1287             /*
    1288              * 32-bit ID pointer to (ID) target within the code (32-bit offset).
    1289              */
    1290             case FIX_ID_32BIT:
    1291             {
    1292                 uint32_t offTrg = *u.pu32++;
    1293                 Assert(offSrc < pSwitcher->cbCode);
    1294                 Assert(offTrg - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offTrg - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    1295                 *uSrc.pu32 = u32IDCode + offTrg;
    1296                 break;
    1297             }
    1298 
    1299             /*
    1300              * 64-bit ID pointer to (ID) target within the code (32-bit offset).
    1301              */
    1302             case FIX_ID_64BIT:
    1303             {
    1304                 uint32_t offTrg = *u.pu32++;
    1305                 Assert(offSrc < pSwitcher->cbCode);
    1306                 Assert(offTrg - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offTrg - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    1307                 *uSrc.pu64 = u32IDCode + offTrg;
    1308                 break;
    1309             }
    1310 
    1311             /*
    1312              * Far 16:32 ID pointer to 64-bit mode (ID) target within the code (32-bit offset).
    1313              */
    1314             case FIX_ID_FAR32_TO_64BIT_MODE:
    1315             {
    1316                 uint32_t offTrg = *u.pu32++;
    1317                 Assert(offSrc < pSwitcher->cbCode);
    1318                 Assert(offTrg - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0 || offTrg - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1);
    1319                 *uSrc.pu32++ = u32IDCode + offTrg;
    1320                 *uSrc.pu16 = SelCS64;
    1321                 AssertRelease(SelCS64);
    1322                 break;
    1323             }
    1324 
    1325 #ifdef VBOX_WITH_NMI
    1326             /*
    1327              * 32-bit address to the APIC base.
    1328              */
    1329             case FIX_GC_APIC_BASE_32BIT:
    1330             {
    1331                 *uSrc.pu32 = pVM->vmm.s.GCPtrApicBase;
    1332                 break;
    1333             }
    1334 #endif
    1335 
    1336             default:
    1337                 AssertReleaseMsgFailed(("Unknown fixup %d in switcher %s\n", u8, pSwitcher->pszDesc));
    1338                 break;
    1339         }
    1340     }
    1341 
    1342 #ifdef LOG_ENABLED
    1343     /*
    1344      * If Log2 is enabled disassemble the switcher code.
    1345      *
    1346      * The switcher code have 1-2 HC parts, 1 GC part and 0-2 ID parts.
    1347      */
    1348     if (LogIs2Enabled())
    1349     {
    1350         RTLogPrintf("*** Disassembly of switcher %d '%s' %#x bytes ***\n"
    1351                     "   pu8CodeR0   = %p\n"
    1352                     "   pu8CodeR3   = %p\n"
    1353                     "   GCPtrCode   = %VGv\n"
    1354                     "   u32IDCode   = %08x\n"
    1355                     "   pVMGC       = %VGv\n"
    1356                     "   pCPUMGC     = %VGv\n"
    1357                     "   pVMHC       = %p\n"
    1358                     "   pCPUMHC     = %p\n"
    1359                     "   GCPtrGDT    = %VGv\n"
    1360                     "   InterCR3s   = %08x, %08x, %08x (32-Bit, PAE, AMD64)\n"
    1361                     "   HyperCR3s   = %08x, %08x, %08x (32-Bit, PAE, AMD64)\n"
    1362                     "   SelCS       = %04x\n"
    1363                     "   SelDS       = %04x\n"
    1364                     "   SelCS64     = %04x\n"
    1365                     "   SelTSS      = %04x\n",
    1366                     pSwitcher->enmType, pSwitcher->pszDesc, pSwitcher->cbCode,
    1367                     pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode, VM_GUEST_ADDR(pVM, pVM),
    1368                     VM_GUEST_ADDR(pVM, &pVM->cpum), pVM, &pVM->cpum,
    1369                     GCPtrGDT,
    1370                     PGMGetHyper32BitCR3(pVM), PGMGetHyperPaeCR3(pVM), PGMGetHyperAmd64CR3(pVM),
    1371                     PGMGetInter32BitCR3(pVM), PGMGetInterPaeCR3(pVM), PGMGetInterAmd64CR3(pVM),
    1372                     SelCS, SelDS, SelCS64, SelTSS);
    1373 
    1374         uint32_t offCode = 0;
    1375         while (offCode < pSwitcher->cbCode)
    1376         {
    1377             /*
    1378              * Figure out where this is.
    1379              */
    1380             const char *pszDesc = NULL;
    1381             RTUINTPTR   uBase;
    1382             uint32_t    cbCode;
    1383             if (offCode - pSwitcher->offHCCode0 < pSwitcher->cbHCCode0)
    1384             {
    1385                 pszDesc = "HCCode0";
    1386                 uBase   = (RTUINTPTR)pu8CodeR0;
    1387                 offCode = pSwitcher->offHCCode0;
    1388                 cbCode  = pSwitcher->cbHCCode0;
    1389             }
    1390             else if (offCode - pSwitcher->offHCCode1 < pSwitcher->cbHCCode1)
    1391             {
    1392                 pszDesc = "HCCode1";
    1393                 uBase   = (RTUINTPTR)pu8CodeR0;
    1394                 offCode = pSwitcher->offHCCode1;
    1395                 cbCode  = pSwitcher->cbHCCode1;
    1396             }
    1397             else if (offCode - pSwitcher->offGCCode < pSwitcher->cbGCCode)
    1398             {
    1399                 pszDesc = "GCCode";
    1400                 uBase   = GCPtrCode;
    1401                 offCode = pSwitcher->offGCCode;
    1402                 cbCode  = pSwitcher->cbGCCode;
    1403             }
    1404             else if (offCode - pSwitcher->offIDCode0 < pSwitcher->cbIDCode0)
    1405             {
    1406                 pszDesc = "IDCode0";
    1407                 uBase   = u32IDCode;
    1408                 offCode = pSwitcher->offIDCode0;
    1409                 cbCode  = pSwitcher->cbIDCode0;
    1410             }
    1411             else if (offCode - pSwitcher->offIDCode1 < pSwitcher->cbIDCode1)
    1412             {
    1413                 pszDesc = "IDCode1";
    1414                 uBase   = u32IDCode;
    1415                 offCode = pSwitcher->offIDCode1;
    1416                 cbCode  = pSwitcher->cbIDCode1;
    1417             }
    1418             else
    1419             {
    1420                 RTLogPrintf("  %04x: %02x '%c' (nowhere)\n",
    1421                             offCode, pu8CodeR3[offCode], isprint(pu8CodeR3[offCode]) ? pu8CodeR3[offCode] : ' ');
    1422                 offCode++;
    1423                 continue;
    1424             }
    1425 
    1426             /*
    1427              * Disassemble it.
    1428              */
    1429             RTLogPrintf("  %s: offCode=%#x cbCode=%#x\n", pszDesc, offCode, cbCode);
    1430             DISCPUSTATE Cpu = {0};
    1431             Cpu.mode = CPUMODE_32BIT;
    1432             while (cbCode > 0)
    1433             {
    1434                 /* try label it */
    1435                 if (pSwitcher->offR0HostToGuest == offCode)
    1436                     RTLogPrintf(" *R0HostToGuest:\n");
    1437                 if (pSwitcher->offGCGuestToHost == offCode)
    1438                     RTLogPrintf(" *GCGuestToHost:\n");
    1439                 if (pSwitcher->offGCCallTrampoline == offCode)
    1440                     RTLogPrintf(" *GCCallTrampoline:\n");
    1441                 if (pSwitcher->offGCGuestToHostAsm == offCode)
    1442                     RTLogPrintf(" *GCGuestToHostAsm:\n");
    1443                 if (pSwitcher->offGCGuestToHostAsmHyperCtx == offCode)
    1444                     RTLogPrintf(" *GCGuestToHostAsmHyperCtx:\n");
    1445                 if (pSwitcher->offGCGuestToHostAsmGuestCtx == offCode)
    1446                     RTLogPrintf(" *GCGuestToHostAsmGuestCtx:\n");
    1447 
    1448                 /* disas */
    1449                 uint32_t cbInstr = 0;
    1450                 char szDisas[256];
    1451                 if (DISInstr(&Cpu, (RTUINTPTR)pu8CodeR3 + offCode, uBase - (RTUINTPTR)pu8CodeR3, &cbInstr, szDisas))
    1452                     RTLogPrintf("  %04x: %s", offCode, szDisas); //for whatever reason szDisas includes '\n'.
    1453                 else
    1454                 {
    1455                     RTLogPrintf("  %04x: %02x '%c'\n",
    1456                                 offCode, pu8CodeR3[offCode], isprint(pu8CodeR3[offCode]) ? pu8CodeR3[offCode] : ' ');
    1457                     cbInstr = 1;
    1458                 }
    1459                 offCode += cbInstr;
    1460                 cbCode -= RT_MIN(cbInstr, cbCode);
    1461             }
    1462         }
    1463     }
    1464 #endif
    1465 }
    1466 
    1467 
    1468 /**
    1469  * Relocator for the 32-Bit to 32-Bit world switcher.
    1470  */
    1471 DECLCALLBACK(void) vmmR3Switcher32BitTo32Bit_Relocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode)
    1472 {
    1473     vmmR3SwitcherGenericRelocate(pVM, pSwitcher, pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode,
    1474                                  SELMGetHyperCS(pVM), SELMGetHyperDS(pVM), SELMGetHyperTSS(pVM), SELMGetHyperGDT(pVM), 0);
    1475 }
    1476 
    1477 
    1478 /**
    1479  * Relocator for the 32-Bit to PAE world switcher.
    1480  */
    1481 DECLCALLBACK(void) vmmR3Switcher32BitToPAE_Relocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode)
    1482 {
    1483     vmmR3SwitcherGenericRelocate(pVM, pSwitcher, pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode,
    1484                                  SELMGetHyperCS(pVM), SELMGetHyperDS(pVM), SELMGetHyperTSS(pVM), SELMGetHyperGDT(pVM), 0);
    1485 }
    1486 
    1487 
    1488 /**
    1489  * Relocator for the PAE to 32-Bit world switcher.
    1490  */
    1491 DECLCALLBACK(void) vmmR3SwitcherPAETo32Bit_Relocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode)
    1492 {
    1493     vmmR3SwitcherGenericRelocate(pVM, pSwitcher, pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode,
    1494                                  SELMGetHyperCS(pVM), SELMGetHyperDS(pVM), SELMGetHyperTSS(pVM), SELMGetHyperGDT(pVM), 0);
    1495 }
    1496 
    1497 
    1498 /**
    1499  * Relocator for the PAE to PAE world switcher.
    1500  */
    1501 DECLCALLBACK(void) vmmR3SwitcherPAEToPAE_Relocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode)
    1502 {
    1503     vmmR3SwitcherGenericRelocate(pVM, pSwitcher, pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode,
    1504                                  SELMGetHyperCS(pVM), SELMGetHyperDS(pVM), SELMGetHyperTSS(pVM), SELMGetHyperGDT(pVM), 0);
    1505 }
    1506 
    1507 
    1508 /**
    1509  * Relocator for the AMD64 to PAE world switcher.
    1510  */
    1511 DECLCALLBACK(void) vmmR3SwitcherAMD64ToPAE_Relocate(PVM pVM, PVMMSWITCHERDEF pSwitcher, uint8_t *pu8CodeR0, uint8_t *pu8CodeR3, RTGCPTR GCPtrCode, uint32_t u32IDCode)
    1512 {
    1513     vmmR3SwitcherGenericRelocate(pVM, pSwitcher, pu8CodeR0, pu8CodeR3, GCPtrCode, u32IDCode,
    1514                                  SELMGetHyperCS(pVM), SELMGetHyperDS(pVM), SELMGetHyperTSS(pVM), SELMGetHyperGDT(pVM), SELMGetHyperCS64(pVM));
    1515 }
    1516 
    1517 
    1518 /**
    1519  * Gets the pointer to g_szRTAssertMsg1 in GC.
    1520  * @returns Pointer to VMMGC::g_szRTAssertMsg1.
    1521  *          Returns NULL if not present.
    1522  * @param   pVM         The VM handle.
    1523  */
    1524 VMMR3DECL(const char *) VMMR3GetGCAssertMsg1(PVM pVM)
    1525 {
    1526     RTGCPTR GCPtr;
    1527     int rc = PDMR3GetSymbolGC(pVM, NULL, "g_szRTAssertMsg1", &GCPtr);
    1528     if (VBOX_SUCCESS(rc))
    1529         return (const char *)MMHyperGC2HC(pVM, GCPtr);
    1530     return NULL;
    1531 }
    1532 
    1533 
    1534 /**
    1535  * Gets the pointer to g_szRTAssertMsg2 in GC.
    1536  * @returns Pointer to VMMGC::g_szRTAssertMsg2.
    1537  *          Returns NULL if not present.
    1538  * @param   pVM         The VM handle.
    1539  */
    1540 VMMR3DECL(const char *) VMMR3GetGCAssertMsg2(PVM pVM)
    1541 {
    1542     RTGCPTR GCPtr;
    1543     int rc = PDMR3GetSymbolGC(pVM, NULL, "g_szRTAssertMsg2", &GCPtr);
    1544     if (VBOX_SUCCESS(rc))
    1545         return (const char *)MMHyperGC2HC(pVM, GCPtr);
    1546     return NULL;
    1547 }
    1548 
    1549 
    1550 /**
    1551  * Execute state save operation.
    1552  *
    1553  * @returns VBox status code.
    1554  * @param   pVM             VM Handle.
    1555  * @param   pSSM            SSM operation handle.
    1556  */
    1557 static DECLCALLBACK(int) vmmR3Save(PVM pVM, PSSMHANDLE pSSM)
    1558 {
    1559     LogFlow(("vmmR3Save:\n"));
    1560 
    1561     /*
    1562      * The hypervisor stack.
    1563      */
    1564     SSMR3PutGCPtr(pSSM, pVM->vmm.s.pbGCStackBottom);
    1565     RTGCPTR GCPtrESP = CPUMGetHyperESP(pVM);
    1566     Assert(pVM->vmm.s.pbGCStackBottom - GCPtrESP <= VMM_STACK_SIZE);
    1567     SSMR3PutGCPtr(pSSM, GCPtrESP);
    1568     SSMR3PutMem(pSSM, pVM->vmm.s.pbHCStack, VMM_STACK_SIZE);
    1569     return SSMR3PutU32(pSSM, ~0); /* terminator */
    1570 }
    1571 
    1572 
    1573 /**
    1574  * Execute state load operation.
    1575  *
    1576  * @returns VBox status code.
    1577  * @param   pVM             VM Handle.
    1578  * @param   pSSM            SSM operation handle.
    1579  * @param   u32Version      Data layout version.
    1580  */
    1581 static DECLCALLBACK(int) vmmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
    1582 {
    1583     LogFlow(("vmmR3Load:\n"));
    1584 
    1585     /*
    1586      * Validate version.
    1587      */
    1588     if (u32Version != VMM_SAVED_STATE_VERSION)
    1589     {
    1590         Log(("vmmR3Load: Invalid version u32Version=%d!\n", u32Version));
    1591         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    1592     }
    1593 
    1594     /*
    1595      * Check that the stack is in the same place, or that it's fearly empty.
    1596      */
    1597     RTGCPTR GCPtrStackBottom;
    1598     SSMR3GetGCPtr(pSSM, &GCPtrStackBottom);
    1599     RTGCPTR GCPtrESP;
    1600     int rc = SSMR3GetGCPtr(pSSM, &GCPtrESP);
    1601     if (VBOX_FAILURE(rc))
    1602         return rc;
    1603     if (    GCPtrStackBottom == pVM->vmm.s.pbGCStackBottom
    1604         ||  (GCPtrStackBottom -  GCPtrESP < 32)) /** @todo This will break if we start preemting the hypervisor. */
    1605     {
    1606         /*
    1607          * We *must* set the ESP because the CPUM load + PGM load relocations will render
    1608          * the ESP in CPUM fatally invalid.
    1609          */
    1610         CPUMSetHyperESP(pVM, GCPtrESP);
    1611 
    1612         /* restore the stack. */
    1613         SSMR3GetMem(pSSM, pVM->vmm.s.pbHCStack, VMM_STACK_SIZE);
    1614 
    1615         /* terminator */
    1616         uint32_t u32;
    1617         rc = SSMR3GetU32(pSSM, &u32);
    1618         if (VBOX_FAILURE(rc))
    1619             return rc;
    1620         if (u32 != ~0U)
    1621         {
    1622             AssertMsgFailed(("u32=%#x\n", u32));
    1623             return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
    1624         }
    1625         return VINF_SUCCESS;
    1626     }
    1627 
    1628     LogRel(("The stack is not in the same place and it's not empty! GCPtrStackBottom=%VGv pbGCStackBottom=%VGv ESP=%VGv\n",
    1629             GCPtrStackBottom, pVM->vmm.s.pbGCStackBottom, GCPtrESP));
    1630     AssertFailed();
    1631     return VERR_SSM_LOAD_CONFIG_MISMATCH;
    1632 }
    1633 
    1634 
    1635 /**
    1636  * Selects the switcher to be used for switching to GC.
    1637  *
    1638  * @returns VBox status code.
    1639  * @param   pVM             VM handle.
    1640  * @param   enmSwitcher     The new switcher.
    1641  * @remark  This function may be called before the VMM is initialized.
    1642  */
    1643 VMMR3DECL(int) VMMR3SelectSwitcher(PVM pVM, VMMSWITCHER enmSwitcher)
    1644 {
    1645     /*
    1646      * Validate input.
    1647      */
    1648     if (    enmSwitcher < VMMSWITCHER_INVALID
    1649         ||  enmSwitcher >= VMMSWITCHER_MAX)
    1650     {
    1651         AssertMsgFailed(("Invalid input enmSwitcher=%d\n", enmSwitcher));
    1652         return VERR_INVALID_PARAMETER;
    1653     }
    1654 
    1655     /*
    1656      * Select the new switcher.
    1657      */
    1658     PVMMSWITCHERDEF pSwitcher = s_apSwitchers[enmSwitcher];
    1659     if (pSwitcher)
    1660     {
    1661         Log(("VMMR3SelectSwitcher: enmSwitcher %d -> %d %s\n", pVM->vmm.s.enmSwitcher, enmSwitcher, pSwitcher->pszDesc));
    1662         pVM->vmm.s.enmSwitcher = enmSwitcher;
    1663 
    1664         RTR0PTR     pbCodeR0 = (RTR0PTR)pVM->vmm.s.pvHCCoreCodeR0 + pVM->vmm.s.aoffSwitchers[enmSwitcher]; /** @todo fix the pvHCCoreCodeR0 type */
    1665         pVM->vmm.s.pfnR0HostToGuest = pbCodeR0 + pSwitcher->offR0HostToGuest;
    1666 
    1667         RTGCPTR     GCPtr = pVM->vmm.s.pvGCCoreCode + pVM->vmm.s.aoffSwitchers[enmSwitcher];
    1668         pVM->vmm.s.pfnGCGuestToHost         = GCPtr + pSwitcher->offGCGuestToHost;
    1669         pVM->vmm.s.pfnGCCallTrampoline      = GCPtr + pSwitcher->offGCCallTrampoline;
    1670         pVM->pfnVMMGCGuestToHostAsm         = GCPtr + pSwitcher->offGCGuestToHostAsm;
    1671         pVM->pfnVMMGCGuestToHostAsmHyperCtx = GCPtr + pSwitcher->offGCGuestToHostAsmHyperCtx;
    1672         pVM->pfnVMMGCGuestToHostAsmGuestCtx = GCPtr + pSwitcher->offGCGuestToHostAsmGuestCtx;
    1673         return VINF_SUCCESS;
    1674     }
    1675     return VERR_NOT_IMPLEMENTED;
    1676 }
    1677 
    1678 /**
    1679  * Disable the switcher logic permanently.
    1680  *
    1681  * @returns VBox status code.
    1682  * @param   pVM             VM handle.
    1683  */
    1684 VMMR3DECL(int) VMMR3DisableSwitcher(PVM pVM)
    1685 {
    1686 /** @todo r=bird: I would suggest that we create a dummy switcher which just does something like:
    1687  * @code
    1688  *       mov eax, VERR_INTERNAL_ERROR
    1689  *       ret
    1690  * @endcode
    1691  * And then check for fSwitcherDisabled in VMMR3SelectSwitcher() in order to prevent it from being removed.
    1692  */
    1693     pVM->vmm.s.fSwitcherDisabled = true;
    1694     return VINF_SUCCESS;
    1695 }
    1696 
    1697 
    1698 /**
    1699  * Resolve a builtin GC symbol.
    1700  * Called by PDM when loading or relocating GC modules.
    1701  *
    1702  * @returns VBox status
    1703  * @param   pVM         VM Handle.
    1704  * @param   pszSymbol   Symbol to resolv
    1705  * @param   pGCPtrValue Where to store the symbol value.
    1706  * @remark  This has to work before VMMR3Relocate() is called.
    1707  */
    1708 VMMR3DECL(int) VMMR3GetImportGC(PVM pVM, const char *pszSymbol, PRTGCPTR pGCPtrValue)
    1709 {
    1710     if (!strcmp(pszSymbol, "g_Logger"))
    1711     {
    1712         if (pVM->vmm.s.pLoggerHC)
    1713             pVM->vmm.s.pLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pLoggerHC);
    1714         *pGCPtrValue = pVM->vmm.s.pLoggerGC;
    1715     }
    1716     else if (!strcmp(pszSymbol, "g_RelLogger"))
    1717     {
    1718 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    1719         if (pVM->vmm.s.pRelLoggerHC)
    1720             pVM->vmm.s.pRelLoggerGC = MMHyperHC2GC(pVM, pVM->vmm.s.pRelLoggerHC);
    1721         *pGCPtrValue = pVM->vmm.s.pRelLoggerGC;
    1722 #else
    1723         *pGCPtrValue = NIL_RTGCPTR;
    1724 #endif
    1725     }
    1726     else
    1727         return VERR_SYMBOL_NOT_FOUND;
    1728     return VINF_SUCCESS;
    1729 }
    1730 
    1731 
    1732 /**
    1733  * Suspends the the CPU yielder.
    1734  *
    1735  * @param   pVM             The VM handle.
    1736  */
    1737 VMMR3DECL(void) VMMR3YieldSuspend(PVM pVM)
    1738 {
    1739     if (!pVM->vmm.s.cYieldResumeMillies)
    1740     {
    1741         uint64_t u64Now = TMTimerGet(pVM->vmm.s.pYieldTimer);
    1742         uint64_t u64Expire = TMTimerGetExpire(pVM->vmm.s.pYieldTimer);
    1743         if (u64Now >= u64Expire || u64Expire == ~(uint64_t)0)
    1744             pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
    1745         else
    1746             pVM->vmm.s.cYieldResumeMillies = TMTimerToMilli(pVM->vmm.s.pYieldTimer, u64Expire - u64Now);
    1747         TMTimerStop(pVM->vmm.s.pYieldTimer);
    1748     }
    1749 }
    1750 
    1751 
    1752 /**
    1753  * Stops the the CPU yielder.
    1754  *
    1755  * @param   pVM             The VM handle.
    1756  */
    1757 VMMR3DECL(void) VMMR3YieldStop(PVM pVM)
    1758 {
    1759     if (!pVM->vmm.s.cYieldResumeMillies)
    1760         TMTimerStop(pVM->vmm.s.pYieldTimer);
    1761     pVM->vmm.s.cYieldResumeMillies = pVM->vmm.s.cYieldEveryMillies;
    1762 }
    1763 
    1764 
    1765 /**
    1766  * Resumes the CPU yielder when it has been a suspended or stopped.
    1767  *
    1768  * @param   pVM             The VM handle.
    1769  */
    1770 VMMR3DECL(void) VMMR3YieldResume(PVM pVM)
    1771 {
    1772     if (pVM->vmm.s.cYieldResumeMillies)
    1773     {
    1774         TMTimerSetMillies(pVM->vmm.s.pYieldTimer, pVM->vmm.s.cYieldResumeMillies);
    1775         pVM->vmm.s.cYieldResumeMillies = 0;
    1776     }
    1777 }
    1778 
    1779 
    1780 /**
    1781  * Internal timer callback function.
    1782  *
    1783  * @param   pVM             The VM.
    1784  * @param   pTimer          The timer handle.
    1785  * @param   pvUser          User argument specified upon timer creation.
    1786  */
    1787 static DECLCALLBACK(void) vmmR3YieldEMT(PVM pVM, PTMTIMER pTimer, void *pvUser)
    1788 {
    1789 #ifdef LOG_ENABLED
    1790     uint64_t u64Elapsed = RTTimeNanoTS();
    1791 #endif
    1792     RTThreadYield();
    1793     TMTimerSetMillies(pTimer, pVM->vmm.s.cYieldEveryMillies);
    1794     Log(("vmmR3YieldEMT: %RI64 ns\n", RTTimeNanoTS() - u64Elapsed));
    1795 }
    1796 
    1797 
    1798 /**
    1799  * Acquire global VM lock.
    1800  *
    1801  * @returns VBox status code
    1802  * @param   pVM         The VM to operate on.
    1803  */
    1804 VMMR3DECL(int) VMMR3Lock(PVM pVM)
    1805 {
    1806     return RTCritSectEnter(&pVM->vmm.s.CritSectVMLock);
    1807 }
    1808 
    1809 
    1810 /**
    1811  * Release global VM lock.
    1812  *
    1813  * @returns VBox status code
    1814  * @param   pVM         The VM to operate on.
    1815  */
    1816 VMMR3DECL(int) VMMR3Unlock(PVM pVM)
    1817 {
    1818     return RTCritSectLeave(&pVM->vmm.s.CritSectVMLock);
    1819 }
    1820 
    1821 
    1822 /**
    1823  * Return global VM lock owner.
    1824  *
    1825  * @returns Thread id of owner.
    1826  * @returns NIL_RTTHREAD if no owner.
    1827  * @param   pVM         The VM to operate on.
    1828  */
    1829 VMMR3DECL(RTNATIVETHREAD) VMMR3LockGetOwner(PVM pVM)
    1830 {
    1831     return RTCritSectGetOwner(&pVM->vmm.s.CritSectVMLock);
    1832 }
    1833 
    1834 
    1835 /**
    1836  * Checks if the current thread is the owner of the global VM lock.
    1837  *
    1838  * @returns true if owner.
    1839  * @returns false if not owner.
    1840  * @param   pVM         The VM to operate on.
    1841  */
    1842 VMMR3DECL(bool) VMMR3LockIsOwner(PVM pVM)
    1843 {
    1844     return RTCritSectIsOwner(&pVM->vmm.s.CritSectVMLock);
    1845 }
    1846 
    1847 
    1848 /**
    1849  * Executes guest code.
    1850  *
    1851  * @param   pVM         VM handle.
    1852  */
    1853 VMMR3DECL(int) VMMR3RawRunGC(PVM pVM)
    1854 {
    1855     Log2(("VMMR3RawRunGC: (cs:eip=%04x:%08x)\n", CPUMGetGuestCS(pVM), CPUMGetGuestEIP(pVM)));
    1856 
    1857     /*
    1858      * Set the EIP and ESP.
    1859      */
    1860     CPUMSetHyperEIP(pVM, CPUMGetGuestEFlags(pVM) & X86_EFL_VM
    1861                     ? pVM->vmm.s.pfnCPUMGCResumeGuestV86
    1862                     : pVM->vmm.s.pfnCPUMGCResumeGuest);
    1863     CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom);
    1864 
    1865     /*
    1866      * We hide log flushes (outer) and hypervisor interrupts (inner).
    1867      */
    1868     for (;;)
    1869     {
    1870         int rc;
    1871         do
    1872         {
    1873 #ifdef NO_SUPCALLR0VMM
    1874             rc = VERR_GENERAL_FAILURE;
    1875 #else
    1876             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    1877 #endif
    1878         } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
    1879 
    1880         /*
    1881          * Flush the logs.
    1882          */
    1883 #ifdef LOG_ENABLED
    1884         PRTLOGGERGC pLogger = pVM->vmm.s.pLoggerHC;
    1885         if (    pLogger
    1886             &&  pLogger->offScratch > 0)
    1887             RTLogFlushGC(NULL, pLogger);
    1888 #endif
    1889 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    1890         PRTLOGGERGC pRelLogger = pVM->vmm.s.pRelLoggerHC;
    1891         if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
    1892             RTLogFlushGC(RTLogRelDefaultInstance(), pRelLogger);
    1893 #endif
    1894         if (rc != VINF_VMM_CALL_HOST)
    1895         {
    1896             Log2(("VMMR3RawRunGC: returns %Vrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVM), CPUMGetGuestEIP(pVM)));
    1897             return rc;
    1898         }
    1899         rc = vmmR3ServiceCallHostRequest(pVM);
    1900         if (VBOX_FAILURE(rc))
    1901             return rc;
    1902         /* Resume GC */
    1903     }
    1904 }
    1905 
    1906 
    1907 /**
    1908  * Executes guest code (Intel VMX and AMD SVM).
    1909  *
    1910  * @param   pVM         VM handle.
    1911  */
    1912 VMMR3DECL(int) VMMR3HwAccRunGC(PVM pVM)
    1913 {
    1914     Log2(("VMMR3HwAccRunGC: (cs:eip=%04x:%08x)\n", CPUMGetGuestCS(pVM), CPUMGetGuestEIP(pVM)));
    1915 
    1916     for (;;)
    1917     {
    1918         int rc;
    1919         do
    1920         {
    1921 #ifdef NO_SUPCALLR0VMM
    1922             rc = VERR_GENERAL_FAILURE;
    1923 #else
    1924             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_HWACC_RUN, NULL);
    1925 #endif
    1926         } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
    1927 
    1928 #ifdef LOG_ENABLED
    1929         /*
    1930          * Flush the log
    1931          */
    1932         PVMMR0LOGGER pR0Logger = pVM->vmm.s.pR0Logger;
    1933         if (    pR0Logger
    1934             &&  pR0Logger->Logger.offScratch > 0)
    1935             RTLogFlushToLogger(&pR0Logger->Logger, NULL);
    1936 #endif /* !LOG_ENABLED */
    1937         if (rc != VINF_VMM_CALL_HOST)
    1938         {
    1939             Log2(("VMMR3HwAccRunGC: returns %Vrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVM), CPUMGetGuestEIP(pVM)));
    1940             return rc;
    1941         }
    1942         rc = vmmR3ServiceCallHostRequest(pVM);
    1943         if (VBOX_FAILURE(rc))
    1944             return rc;
    1945         /* Resume R0 */
    1946     }
    1947 }
    1948 
    1949 /**
    1950  * Calls GC a function.
    1951  *
    1952  * @param   pVM         The VM handle.
    1953  * @param   GCPtrEntry  The GC function address.
    1954  * @param   cArgs       The number of arguments in the ....
    1955  * @param   ...         Arguments to the function.
    1956  */
    1957 VMMR3DECL(int) VMMR3CallGC(PVM pVM, RTGCPTR GCPtrEntry, unsigned cArgs, ...)
    1958 {
    1959     va_list args;
    1960     va_start(args, cArgs);
    1961     int rc = VMMR3CallGCV(pVM, GCPtrEntry, cArgs, args);
    1962     va_end(args);
    1963     return rc;
    1964 }
    1965 
    1966 
    1967 /**
    1968  * Calls GC a function.
    1969  *
    1970  * @param   pVM         The VM handle.
    1971  * @param   GCPtrEntry  The GC function address.
    1972  * @param   cArgs       The number of arguments in the ....
    1973  * @param   args        Arguments to the function.
    1974  */
    1975 VMMR3DECL(int) VMMR3CallGCV(PVM pVM, RTGCPTR GCPtrEntry, unsigned cArgs, va_list args)
    1976 {
    1977     Log2(("VMMR3CallGCV: GCPtrEntry=%VGv cArgs=%d\n", GCPtrEntry, cArgs));
    1978 
    1979     /*
    1980      * Setup the call frame using the trampoline.
    1981      */
    1982     CPUMHyperSetCtxCore(pVM, NULL);
    1983     memset(pVM->vmm.s.pbHCStack, 0xaa, VMM_STACK_SIZE); /* Clear the stack. */
    1984     CPUMSetHyperESP(pVM, pVM->vmm.s.pbGCStackBottom - cArgs * sizeof(RTGCUINTPTR));
    1985     PRTGCUINTPTR pFrame = (PRTGCUINTPTR)(pVM->vmm.s.pbHCStack + VMM_STACK_SIZE) - cArgs;
    1986     int i = cArgs;
    1987     while (i-- > 0)
    1988         *pFrame++ = va_arg(args, RTGCUINTPTR);
    1989 
    1990     CPUMPushHyper(pVM, cArgs * sizeof(RTGCUINTPTR));                          /* stack frame size */
    1991     CPUMPushHyper(pVM, GCPtrEntry);                                             /* what to call */
    1992     CPUMSetHyperEIP(pVM, pVM->vmm.s.pfnGCCallTrampoline);
    1993 
    1994     /*
    1995      * We hide log flushes (outer) and hypervisor interrupts (inner).
    1996      */
    1997     for (;;)
    1998     {
    1999         int rc;
    2000         do
    2001         {
    2002 #ifdef NO_SUPCALLR0VMM
    2003             rc = VERR_GENERAL_FAILURE;
    2004 #else
    2005             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2006 #endif
    2007         } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
    2008 
    2009         /*
    2010          * Flush the logs.
    2011          */
    2012 #ifdef LOG_ENABLED
    2013         PRTLOGGERGC pLogger = pVM->vmm.s.pLoggerHC;
    2014         if (    pLogger
    2015             &&  pLogger->offScratch > 0)
    2016             RTLogFlushGC(NULL, pLogger);
    2017 #endif
    2018 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    2019         PRTLOGGERGC pRelLogger = pVM->vmm.s.pRelLoggerHC;
    2020         if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
    2021             RTLogFlushGC(RTLogRelDefaultInstance(), pRelLogger);
    2022 #endif
    2023         if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
    2024             VMMR3FatalDump(pVM, rc);
    2025         if (rc != VINF_VMM_CALL_HOST)
    2026         {
    2027             Log2(("VMMR3CallGCV: returns %Vrc (cs:eip=%04x:%08x)\n", rc, CPUMGetGuestCS(pVM), CPUMGetGuestEIP(pVM)));
    2028             return rc;
    2029         }
    2030         rc = vmmR3ServiceCallHostRequest(pVM);
    2031         if (VBOX_FAILURE(rc))
    2032             return rc;
    2033     }
    2034 }
    2035 
    2036 
    2037 /**
    2038  * Resumes executing hypervisor code when interrupted
    2039  * by a queue flush or a debug event.
    2040  *
    2041  * @returns VBox status code.
    2042  * @param   pVM         VM handle.
    2043  */
    2044 VMMR3DECL(int) VMMR3ResumeHyper(PVM pVM)
    2045 {
    2046     Log(("VMMR3ResumeHyper: eip=%VGv esp=%VGv\n", CPUMGetHyperEIP(pVM), CPUMGetHyperESP(pVM)));
    2047 
    2048     /*
    2049      * We hide log flushes (outer) and hypervisor interrupts (inner).
    2050      */
    2051     for (;;)
    2052     {
    2053         int rc;
    2054         do
    2055         {
    2056 #ifdef NO_SUPCALLR0VMM
    2057             rc = VERR_GENERAL_FAILURE;
    2058 #else
    2059             rc = SUPCallVMMR0(pVM->pVMR0, VMMR0_DO_RAW_RUN, NULL);
    2060 #endif
    2061         } while (rc == VINF_EM_RAW_INTERRUPT_HYPER);
    2062 
    2063         /*
    2064          * Flush the loggers,
    2065          */
    2066 #ifdef LOG_ENABLED
    2067         PRTLOGGERGC pLogger = pVM->vmm.s.pLoggerHC;
    2068         if (    pLogger
    2069             &&  pLogger->offScratch > 0)
    2070             RTLogFlushGC(NULL, pLogger);
    2071 #endif
    2072 #ifdef VBOX_WITH_GC_AND_R0_RELEASE_LOG
    2073         PRTLOGGERGC pRelLogger = pVM->vmm.s.pRelLoggerHC;
    2074         if (RT_UNLIKELY(pRelLogger && pRelLogger->offScratch > 0))
    2075             RTLogFlushGC(RTLogRelDefaultInstance(), pRelLogger);
    2076 #endif
    2077         if (rc == VERR_TRPM_PANIC || rc == VERR_TRPM_DONT_PANIC)
    2078             VMMR3FatalDump(pVM, rc);
    2079         if (rc != VINF_VMM_CALL_HOST)
    2080         {
    2081             Log(("VMMR3ResumeHyper: returns %Vrc\n", rc));
    2082             return rc;
    2083         }
    2084         rc = vmmR3ServiceCallHostRequest(pVM);
    2085         if (VBOX_FAILURE(rc))
    2086             return rc;
    2087     }
    2088 }
    2089 
    2090 
    2091 /**
    2092  * Service a call to the ring-3 host code.
    2093  *
    2094  * @returns VBox status code.
    2095  * @param   pVM     VM handle.
    2096  * @remark  Careful with critsects.
    2097  */
    2098 static int vmmR3ServiceCallHostRequest(PVM pVM)
    2099 {
    2100     switch (pVM->vmm.s.enmCallHostOperation)
    2101     {
    2102         /*
    2103          * Acquire the PDM lock.
    2104          */
    2105         case VMMCALLHOST_PDM_LOCK:
    2106         {
    2107             pVM->vmm.s.rcCallHost = PDMR3LockCall(pVM);
    2108             break;
    2109         }
    2110 
    2111         /*
    2112          * Flush a PDM queue.
    2113          */
    2114         case VMMCALLHOST_PDM_QUEUE_FLUSH:
    2115         {
    2116             PDMR3QueueFlushWorker(pVM, NULL);
    2117             pVM->vmm.s.rcCallHost = VINF_SUCCESS;
    2118             break;
    2119         }
    2120 
    2121         /*
    2122          * Grow the PGM pool.
    2123          */
    2124         case VMMCALLHOST_PGM_POOL_GROW:
    2125         {
    2126             pVM->vmm.s.rcCallHost = PGMR3PoolGrow(pVM);
    2127             break;
    2128         }
    2129 
    2130         /*
    2131          * Acquire the PGM lock.
    2132          */
    2133         case VMMCALLHOST_PGM_LOCK:
    2134         {
    2135             pVM->vmm.s.rcCallHost = PGMR3LockCall(pVM);
    2136             break;
    2137         }
    2138 
    2139         /*
    2140          * Flush REM handler notifications.
    2141          */
    2142         case VMMCALLHOST_REM_REPLAY_HANDLER_NOTIFICATIONS:
    2143         {
    2144             REMR3ReplayHandlerNotifications(pVM);
    2145             break;
    2146         }
    2147 
    2148         case VMMCALLHOST_PGM_RAM_GROW_RANGE:
    2149         {
    2150             pVM->vmm.s.rcCallHost = PGM3PhysGrowRange(pVM, pVM->vmm.s.u64CallHostArg);
    2151             break;
    2152         }
    2153 
    2154         /*
    2155          * This is a noop. We just take this route to avoid unnecessary
    2156          * tests in the loops.
    2157          */
    2158         case VMMCALLHOST_VMM_LOGGER_FLUSH:
    2159             break;
    2160 
    2161         /*
    2162          * Set the VM error message.
    2163          */
    2164         case VMMCALLHOST_VM_SET_ERROR:
    2165             VMR3SetErrorWorker(pVM);
    2166             break;
    2167 
    2168         /*
    2169          * Set the VM runtime error message.
    2170          */
    2171         case VMMCALLHOST_VM_SET_RUNTIME_ERROR:
    2172             VMR3SetRuntimeErrorWorker(pVM);
    2173             break;
    2174 
    2175         default:
    2176             AssertMsgFailed(("enmCallHostOperation=%d\n", pVM->vmm.s.enmCallHostOperation));
    2177             return VERR_INTERNAL_ERROR;
    2178     }
    2179 
    2180     pVM->vmm.s.enmCallHostOperation = VMMCALLHOST_INVALID;
    2181     return VINF_SUCCESS;
    2182 }
    2183 
    2184 
    2185 
    2186 /**
    2187  * Structure to pass to DBGFR3Info() and for doing all other
    2188  * output during fatal dump.
    2189  */
    2190 typedef struct VMMR3FATALDUMPINFOHLP
    2191 {
    2192     /** The helper core. */
    2193     DBGFINFOHLP Core;
    2194     /** The release logger instance. */
    2195     PRTLOGGER   pRelLogger;
    2196     /** The saved release logger flags. */
    2197     RTUINT      fRelLoggerFlags;
    2198     /** The logger instance. */
    2199     PRTLOGGER   pLogger;
    2200     /** The saved logger flags. */
    2201     RTUINT      fLoggerFlags;
    2202     /** The saved logger destination flags. */
    2203     RTUINT      fLoggerDestFlags;
    2204     /** Whether to output to stderr or not. */
    2205     bool        fStdErr;
    2206 } VMMR3FATALDUMPINFOHLP, *PVMMR3FATALDUMPINFOHLP;
    2207 typedef const VMMR3FATALDUMPINFOHLP *PCVMMR3FATALDUMPINFOHLP;
    2208 
    2209 
    2210 /**
    2211  * Print formatted string.
    2212  *
    2213  * @param   pHlp        Pointer to this structure.
    2214  * @param   pszFormat   The format string.
    2215  * @param   ...         Arguments.
    2216  */
    2217 static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
    2218 {
    2219     va_list args;
    2220     va_start(args, pszFormat);
    2221     pHlp->pfnPrintfV(pHlp, pszFormat, args);
    2222     va_end(args);
    2223 }
    2224 
    2225 
    2226 /**
    2227  * Print formatted string.
    2228  *
    2229  * @param   pHlp        Pointer to this structure.
    2230  * @param   pszFormat   The format string.
    2231  * @param   args        Argument list.
    2232  */
    2233 static DECLCALLBACK(void) vmmR3FatalDumpInfoHlp_pfnPrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
    2234 {
    2235     PCVMMR3FATALDUMPINFOHLP pMyHlp = (PCVMMR3FATALDUMPINFOHLP)pHlp;
    2236 
    2237     if (pMyHlp->pRelLogger)
    2238     {
    2239         va_list args2;
    2240         va_copy(args2, args);
    2241         RTLogLoggerV(pMyHlp->pRelLogger, pszFormat, args2);
    2242         va_end(args2);
    2243     }
    2244     if (pMyHlp->pLogger)
    2245     {
    2246         va_list args2;
    2247         va_copy(args2, args);
    2248         RTLogLoggerV(pMyHlp->pLogger, pszFormat, args);
    2249         va_end(args2);
    2250     }
    2251     if (pMyHlp->fStdErr)
    2252     {
    2253         va_list args2;
    2254         va_copy(args2, args);
    2255         RTStrmPrintfV(g_pStdErr, pszFormat, args);
    2256         va_end(args2);
    2257     }
    2258 }
    2259 
    2260 
    2261 /**
    2262  * Initializes the fatal dump output helper.
    2263  *
    2264  * @param   pHlp        The structure to initialize.
    2265  */
    2266 static void vmmR3FatalDumpInfoHlpInit(PVMMR3FATALDUMPINFOHLP pHlp)
    2267 {
    2268     memset(pHlp, 0, sizeof(*pHlp));
    2269 
    2270     pHlp->Core.pfnPrintf = vmmR3FatalDumpInfoHlp_pfnPrintf;
    2271     pHlp->Core.pfnPrintfV = vmmR3FatalDumpInfoHlp_pfnPrintfV;
    2272 
    2273     /*
    2274      * The loggers.
    2275      */
    2276     pHlp->pRelLogger = RTLogRelDefaultInstance();
    2277 #ifndef LOG_ENABLED
    2278     if (!pHlp->pRelLogger)
    2279 #endif
    2280         pHlp->pLogger = RTLogDefaultInstance();
    2281 
    2282     if (pHlp->pRelLogger)
    2283     {
    2284         pHlp->fRelLoggerFlags = pHlp->pRelLogger->fFlags;
    2285         pHlp->pRelLogger->fFlags &= ~(RTLOGFLAGS_BUFFERED | RTLOGFLAGS_DISABLED);
    2286     }
    2287 
    2288     if (pHlp->pLogger)
    2289     {
    2290         pHlp->fLoggerFlags     = pHlp->pLogger->fFlags;
    2291         pHlp->fLoggerDestFlags = pHlp->pLogger->fDestFlags;
    2292         pHlp->pLogger->fFlags     &= ~(RTLOGFLAGS_BUFFERED | RTLOGFLAGS_DISABLED);
    2293         pHlp->pLogger->fDestFlags |= RTLOGDEST_DEBUGGER;
    2294     }
    2295 
    2296     /*
    2297      * Check if we need write to stderr.
    2298      */
    2299     pHlp->fStdErr = (!pHlp->pRelLogger || !(pHlp->pRelLogger->fDestFlags & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)))
    2300                  && (!pHlp->pLogger || !(pHlp->pLogger->fDestFlags & (RTLOGDEST_STDOUT | RTLOGDEST_STDERR)));
    2301 }
    2302 
    2303 
    2304 /**
    2305  * Deletes the fatal dump output helper.
    2306  *
    2307  * @param   pHlp        The structure to delete.
    2308  */
    2309 static void vmmR3FatalDumpInfoHlpDelete(PVMMR3FATALDUMPINFOHLP pHlp)
    2310 {
    2311     if (pHlp->pRelLogger)
    2312     {
    2313         RTLogFlush(pHlp->pRelLogger);
    2314         pHlp->pRelLogger->fFlags = pHlp->fRelLoggerFlags;
    2315     }
    2316 
    2317     if (pHlp->pLogger)
    2318     {
    2319         RTLogFlush(pHlp->pLogger);
    2320         pHlp->pLogger->fFlags     = pHlp->fLoggerFlags;
    2321         pHlp->pLogger->fDestFlags = pHlp->fLoggerDestFlags;
    2322     }
    2323 }
    2324 
    2325 
    2326 /**
    2327  * Dumps the VM state on a fatal error.
    2328  *
    2329  * @param   pVM         VM Handle.
    2330  * @param   rcErr       VBox status code.
    2331  */
    2332 VMMR3DECL(void) VMMR3FatalDump(PVM pVM, int rcErr)
    2333 {
    2334     /*
    2335      * Create our output helper and sync it with the log settings.
    2336      * This helper will be used for all the output.
    2337      */
    2338     VMMR3FATALDUMPINFOHLP   Hlp;
    2339     PCDBGFINFOHLP           pHlp = &Hlp.Core;
    2340     vmmR3FatalDumpInfoHlpInit(&Hlp);
    2341 
    2342     /*
    2343      * Header.
    2344      */
    2345     pHlp->pfnPrintf(pHlp,
    2346                     "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
    2347                     "!!\n"
    2348                     "!!                 Guru Meditation %d (%Vrc)\n"
    2349                     "!!\n",
    2350                     rcErr, rcErr);
    2351 
    2352     /*
    2353      * Continue according to context.
    2354      */
    2355     bool fDoneHyper = false;
    2356     switch (rcErr)
    2357     {
    2358         /*
    2359          * Hyper visor errors.
    2360          */
    2361         case VINF_EM_DBG_HYPER_ASSERTION:
    2362             pHlp->pfnPrintf(pHlp, "%s%s!!\n", VMMR3GetGCAssertMsg1(pVM), VMMR3GetGCAssertMsg2(pVM));
    2363             /* fall thru */
    2364         case VERR_TRPM_DONT_PANIC:
    2365         case VERR_TRPM_PANIC:
    2366         case VINF_EM_RAW_STALE_SELECTOR:
    2367         case VINF_EM_RAW_IRET_TRAP:
    2368         case VINF_EM_DBG_HYPER_BREAKPOINT:
    2369         case VINF_EM_DBG_HYPER_STEPPED:
    2370         {
    2371             /* Trap? */
    2372             uint32_t        uEIP = CPUMGetHyperEIP(pVM);
    2373             bool            fSoftwareInterrupt = false;
    2374             uint8_t         u8TrapNo   =       0xce;
    2375             RTGCUINT        uErrorCode = 0xdeadface;
    2376             RTGCUINTPTR     uCR2       = 0xdeadface;
    2377             int rc2 = TRPMQueryTrapAll(pVM, &u8TrapNo, &fSoftwareInterrupt, &uErrorCode, &uCR2);
    2378             if (VBOX_SUCCESS(rc2))
    2379                 pHlp->pfnPrintf(pHlp,
    2380                                 "!! TRAP=%02x ERRCD=%VGv CR2=%VGv EIP=%VGv fSoft=%d\n",
    2381                                 u8TrapNo, uErrorCode, uCR2, uEIP, fSoftwareInterrupt);
    2382             else
    2383                 pHlp->pfnPrintf(pHlp,
    2384                                 "!! EIP=%VGv NOTRAP\n",
    2385                                 uEIP);
    2386 
    2387             /*
    2388              * Try figure out where eip is.
    2389              */
    2390             /** @todo make query call for core code or move this function to VMM. */
    2391             /* core code? */
    2392             //if (uEIP - (RTGCUINTPTR)pVM->vmm.s.pvGCCoreCode < pVM->vmm.s.cbCoreCode)
    2393             //    pHlp->pfnPrintf(pHlp,
    2394             //                "!! EIP is in CoreCode, offset %#x\n",
    2395             //                uEIP - (RTGCUINTPTR)pVM->vmm.s.pvGCCoreCode);
    2396             //else
    2397             {   /* ask PDM */
    2398                 /** @todo ask DBGFR3Sym later. */
    2399                 char        szModName[64];
    2400                 RTGCPTR     GCPtrMod;
    2401                 char        szNearSym1[260];
    2402                 RTGCPTR     GCPtrNearSym1;
    2403                 char        szNearSym2[260];
    2404                 RTGCPTR     GCPtrNearSym2;
    2405                 int rc = PDMR3QueryModFromEIP(pVM, uEIP,
    2406                                               &szModName[0],  sizeof(szModName),  &GCPtrMod,
    2407                                               &szNearSym1[0], sizeof(szNearSym1), &GCPtrNearSym1,
    2408                                               &szNearSym2[0], sizeof(szNearSym2), &GCPtrNearSym2);
    2409                 if (VBOX_SUCCESS(rc))
    2410                 {
    2411                     pHlp->pfnPrintf(pHlp,
    2412                                     "!! EIP in %s (%p) at rva %x near symbols:\n"
    2413                                     "!!    %VGv rva %VGv off %08x  %s\n"
    2414                                     "!!    %VGv rva %VGv off -%08x %s\n",
    2415                                     szModName,  GCPtrMod, (unsigned)(uEIP - GCPtrMod),
    2416                                     GCPtrNearSym1, GCPtrNearSym1 - GCPtrMod, (unsigned)(uEIP - GCPtrNearSym1), szNearSym1,
    2417                                     GCPtrNearSym2, GCPtrNearSym2 - GCPtrMod, (unsigned)(GCPtrNearSym2 - uEIP), szNearSym2);
    2418                 }
    2419                 else
    2420                     pHlp->pfnPrintf(pHlp,
    2421                                     "!! EIP is not in any code known to VMM!\n");
    2422             }
    2423 
    2424             /* Disassemble the instruction. */
    2425             char szInstr[256];
    2426             rc2 = DBGFR3DisasInstrEx(pVM, 0, 0, DBGF_DISAS_FLAGS_CURRENT_HYPER, &szInstr[0], sizeof(szInstr), NULL);
    2427             if (VBOX_SUCCESS(rc2))
    2428                 pHlp->pfnPrintf(pHlp,
    2429                                 "!! %s\n", szInstr);
    2430 
    2431             /* Dump the hypervisor cpu state. */
    2432             pHlp->pfnPrintf(pHlp,
    2433                             "!!\n"
    2434                             "!!\n"
    2435                             "!!\n");
    2436             rc2 = DBGFR3Info(pVM, "cpumhyper", "verbose", pHlp);
    2437             fDoneHyper = true;
    2438 
    2439             /* Callstack. */
    2440             DBGFSTACKFRAME Frame = {0};
    2441             rc2 = DBGFR3StackWalkBeginHyper(pVM, &Frame);
    2442             if (VBOX_SUCCESS(rc2))
    2443             {
    2444                 pHlp->pfnPrintf(pHlp,
    2445                                 "!!\n"
    2446                                 "!! Call Stack:\n"
    2447                                 "!!\n"
    2448                                 "EBP      Ret EBP  Ret CS:EIP    Arg0     Arg1     Arg2     Arg3     CS:EIP        Symbol [line]\n");
    2449                 do
    2450                 {
    2451                     pHlp->pfnPrintf(pHlp,
    2452                                     "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
    2453                                     (uint32_t)Frame.AddrFrame.off,
    2454                                     (uint32_t)Frame.AddrReturnFrame.off,
    2455                                     (uint32_t)Frame.AddrReturnPC.Sel,
    2456                                     (uint32_t)Frame.AddrReturnPC.off,
    2457                                     Frame.Args.au32[0],
    2458                                     Frame.Args.au32[1],
    2459                                     Frame.Args.au32[2],
    2460                                     Frame.Args.au32[3]);
    2461                     pHlp->pfnPrintf(pHlp, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);
    2462                     if (Frame.pSymPC)
    2463                     {
    2464                         RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value;
    2465                         if (offDisp > 0)
    2466                             pHlp->pfnPrintf(pHlp, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);
    2467                         else if (offDisp < 0)
    2468                             pHlp->pfnPrintf(pHlp, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);
    2469                         else
    2470                             pHlp->pfnPrintf(pHlp, " %s", Frame.pSymPC->szName);
    2471                     }
    2472                     if (Frame.pLinePC)
    2473                         pHlp->pfnPrintf(pHlp, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);
    2474                     pHlp->pfnPrintf(pHlp, "\n");
    2475 
    2476                     /* next */
    2477                     rc2 = DBGFR3StackWalkNext(pVM, &Frame);
    2478                 } while (VBOX_SUCCESS(rc2));
    2479                 DBGFR3StackWalkEnd(pVM, &Frame);
    2480             }
    2481 
    2482             /* raw stack */
    2483             pHlp->pfnPrintf(pHlp,
    2484                             "!!\n"
    2485                             "!! Raw stack (mind the direction).\n"
    2486                             "!!\n"
    2487                             "%.*Vhxd\n",
    2488                             VMM_STACK_SIZE, (char *)pVM->vmm.s.pbHCStack);
    2489             break;
    2490         }
    2491 
    2492         default:
    2493         {
    2494             break;
    2495         }
    2496 
    2497     } /* switch (rcErr) */
    2498 
    2499 
    2500     /*
    2501      * Dump useful state information.
    2502      */
    2503     /** @todo convert these dumpers to DBGFR3Info() handlers!!! */
    2504     pHlp->pfnPrintf(pHlp,
    2505                     "!!\n"
    2506                     "!! PGM Access Handlers & Stuff:\n"
    2507                     "!!\n");
    2508     PGMR3DumpMappings(pVM);
    2509 
    2510 
    2511     /*
    2512      * Generic info dumper loop.
    2513      */
    2514     static struct
    2515     {
    2516         const char *pszInfo;
    2517         const char *pszArgs;
    2518     } const     aInfo[] =
    2519     {
    2520         { "hma",            NULL },
    2521         { "cpumguest",      "verbose" },
    2522         { "cpumhyper",      "verbose" },
    2523         { "cpumhost",       "verbose" },
    2524         { "mode",           "all" },
    2525         { "cpuid",          "verbose" },
    2526         { "gdt",            NULL },
    2527         { "ldt",            NULL },
    2528         //{ "tss",            NULL },
    2529         { "ioport",         NULL },
    2530         { "mmio",           NULL },
    2531         { "phys",           NULL },
    2532         //{ "pgmpd",          NULL }, - doesn't always work at init time...
    2533         { "timers",         NULL },
    2534         { "activetimers",   NULL },
    2535         { "handlers",       "phys virt stats" },
    2536         { "cfgm",           NULL },
    2537     };
    2538     for (unsigned i = 0; i < ELEMENTS(aInfo); i++)
    2539     {
    2540         if (fDoneHyper && !strcmp(aInfo[i].pszInfo, "cpumhyper"))
    2541             continue;
    2542         pHlp->pfnPrintf(pHlp,
    2543                         "!!\n"
    2544                         "!! {%s, %s}\n"
    2545                         "!!\n",
    2546                         aInfo[i].pszInfo, aInfo[i].pszArgs);
    2547         DBGFR3Info(pVM, aInfo[i].pszInfo, aInfo[i].pszArgs, pHlp);
    2548     }
    2549 
    2550     /* done */
    2551     pHlp->pfnPrintf(pHlp,
    2552                     "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    2553 
    2554 
    2555     /*
    2556      * Delete the output instance (flushing and restoring of flags).
    2557      */
    2558     vmmR3FatalDumpInfoHlpDelete(&Hlp);
    2559 }
    256046
    256147
     
    3078564    return rc;
    3079565}
     566
Note: See TracChangeset for help on using the changeset viewer.

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