Пример #1
0
/**
 * The GC entry point.
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   uOperation  Which operation to execute (VMMGCOPERATION).
 * @param   uArg        Argument to that operation.
 */
VMMRCDECL(int) VMMGCEntry(PVM pVM, unsigned uOperation, unsigned uArg, ...)
{
    /* todo */
    switch (uOperation)
    {
        /*
         * Init RC modules.
         */
        case VMMGC_DO_VMMGC_INIT:
        {
            /*
             * Validate the svn revision (uArg).
             */
            if (uArg != VMMGetSvnRev())
                return VERR_VMM_RC_VERSION_MISMATCH;

            /*
             * Initialize the runtime.
             * (The program timestamp is found in the elipsis.)
             */
            va_list va;
            va_start(va, uArg);
            uint64_t u64TS = va_arg(va, uint64_t);
            va_end(va);

            int rc = RTRCInit(u64TS);
            Log(("VMMGCEntry: VMMGC_DO_VMMGC_INIT - uArg=%u (svn revision) u64TS=%RX64; rc=%Rrc\n", uArg, u64TS, rc));
            AssertRCReturn(rc, rc);

            rc = PGMRegisterStringFormatTypes();
            AssertRCReturn(rc, rc);

            rc = PGMRCDynMapInit(pVM);
            AssertRCReturn(rc, rc);
            return VINF_SUCCESS;
        }

        /*
         * Testcase which is used to test interrupt forwarding.
         * It spins for a while with interrupts enabled.
         */
        case VMMGC_DO_TESTCASE_HYPER_INTERRUPT:
        {
            uint32_t volatile i = 0;
            ASMIntEnable();
            while (i < _2G32)
                i++;
            ASMIntDisable();
            return 0;
        }

        /*
         * Testcase which simply returns, this is used for
         * profiling of the switcher.
         */
        case VMMGC_DO_TESTCASE_NOP:
            return 0;

        /*
         * Testcase executes a privileged instruction to force a world switch. (in both SVM & VMX)
         */
        case VMMGC_DO_TESTCASE_HWACCM_NOP:
            ASMRdMsr_Low(MSR_IA32_SYSENTER_CS);
            return 0;

        /*
         * Delay for ~100us.
         */
        case VMMGC_DO_TESTCASE_INTERRUPT_MASKING:
        {
            uint64_t u64MaxTicks = (SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage) != ~(uint64_t)0
                                    ? SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage)
                                    : _2G)
                                   / 10000;
            uint64_t u64StartTSC = ASMReadTSC();
            uint64_t u64TicksNow;
            uint32_t volatile i = 0;

            do
            {
                /* waste some time and protect against getting stuck. */
                for (uint32_t volatile j = 0; j < 1000; j++, i++)
                    if (i > _2G32)
                        return VERR_GENERAL_FAILURE;

                /* check if we're done.*/
                u64TicksNow = ASMReadTSC() - u64StartTSC;
            } while (u64TicksNow < u64MaxTicks);

            return VINF_SUCCESS;
        }

        /*
         * Trap testcases and unknown operations.
         */
        default:
            if (    uOperation >= VMMGC_DO_TESTCASE_TRAP_FIRST
                &&  uOperation < VMMGC_DO_TESTCASE_TRAP_LAST)
                return vmmGCTest(pVM, uOperation, uArg);
            return VERR_INVALID_PARAMETER;
    }
}
/**
 * Worker function for dbgfR3CoreWrite() which does the writing.
 *
 * @returns VBox status code
 * @param   pVM                 Pointer to the VM.
 * @param   hFile               The file to write to.  Caller closes this.
 */
static int dbgfR3CoreWriteWorker(PVM pVM, RTFILE hFile)
{
    /*
     * Collect core information.
     */
    uint32_t const cu32MemRanges = dbgfR3GetRamRangeCount(pVM);
    uint16_t const cMemRanges    = cu32MemRanges < UINT16_MAX - 1 ? cu32MemRanges : UINT16_MAX - 1; /* One PT_NOTE Program header */
    uint16_t const cProgHdrs     = cMemRanges + 1;

    DBGFCOREDESCRIPTOR CoreDescriptor;
    RT_ZERO(CoreDescriptor);
    CoreDescriptor.u32Magic           = DBGFCORE_MAGIC;
    CoreDescriptor.u32FmtVersion      = DBGFCORE_FMT_VERSION;
    CoreDescriptor.cbSelf             = sizeof(CoreDescriptor);
    CoreDescriptor.u32VBoxVersion     = VBOX_FULL_VERSION;
    CoreDescriptor.u32VBoxRevision    = VMMGetSvnRev();
    CoreDescriptor.cCpus              = pVM->cCpus;

    Log((DBGFLOG_NAME ": CoreDescriptor Version=%u Revision=%u\n", CoreDescriptor.u32VBoxVersion, CoreDescriptor.u32VBoxRevision));

    /*
     * Compute the file layout (see pg_dbgf_vmcore).
     */
    uint64_t const offElfHdr          = RTFileTell(hFile);
    uint64_t const offNoteSection     = offElfHdr         + sizeof(Elf64_Ehdr);
    uint64_t const offLoadSections    = offNoteSection    + sizeof(Elf64_Phdr);
    uint64_t const cbLoadSections     = cMemRanges * sizeof(Elf64_Phdr);
    uint64_t const offCoreDescriptor  = offLoadSections   + cbLoadSections;
    uint64_t const cbCoreDescriptor   = Elf64NoteSectionSize(g_pcszCoreVBoxCore, sizeof(CoreDescriptor));
    uint64_t const offCpuDumps        = offCoreDescriptor + cbCoreDescriptor;
    uint64_t const cbCpuDumps         = pVM->cCpus * Elf64NoteSectionSize(g_pcszCoreVBoxCpu, sizeof(DBGFCORECPU));
    uint64_t const offMemory          = offCpuDumps       + cbCpuDumps;

    uint64_t const offNoteSectionData = offCoreDescriptor;
    uint64_t const cbNoteSectionData  = cbCoreDescriptor + cbCpuDumps;

    /*
     * Write ELF header.
     */
    int rc = Elf64WriteElfHdr(hFile, cProgHdrs, 0 /* cSecHdrs */);
    if (RT_FAILURE(rc))
    {
        LogRel((DBGFLOG_NAME ": Elf64WriteElfHdr failed. rc=%Rrc\n", rc));
        return rc;
    }

    /*
     * Write PT_NOTE program header.
     */
    Assert(RTFileTell(hFile) == offNoteSection);
    rc = Elf64WriteProgHdr(hFile, PT_NOTE, PF_R,
                           offNoteSectionData,  /* file offset to contents */
                           cbNoteSectionData,   /* size in core file */
                           cbNoteSectionData,   /* size in memory */
                           0);                  /* physical address */
    if (RT_FAILURE(rc))
    {
        LogRel((DBGFLOG_NAME ": Elf64WritreProgHdr failed for PT_NOTE. rc=%Rrc\n", rc));
        return rc;
    }

    /*
     * Write PT_LOAD program header for each memory range.
     */
    Assert(RTFileTell(hFile) == offLoadSections);
    uint64_t offMemRange = offMemory;
    for (uint16_t iRange = 0; iRange < cMemRanges; iRange++)
    {
        RTGCPHYS    GCPhysStart;
        RTGCPHYS    GCPhysEnd;
        bool        fIsMmio;
        rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, &fIsMmio);
        if (RT_FAILURE(rc))
        {
            LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n", iRange, rc));
            return rc;
        }

        uint64_t cbMemRange  = GCPhysEnd - GCPhysStart + 1;
        uint64_t cbFileRange = fIsMmio ? 0 : cbMemRange;

        Log((DBGFLOG_NAME ": PGMR3PhysGetRange iRange=%u GCPhysStart=%#x GCPhysEnd=%#x cbMemRange=%u\n",
             iRange, GCPhysStart, GCPhysEnd, cbMemRange));

        rc = Elf64WriteProgHdr(hFile, PT_LOAD, PF_R,
                               offMemRange,                         /* file offset to contents */
                               cbFileRange,                         /* size in core file */
                               cbMemRange,                          /* size in memory */
                               GCPhysStart);                        /* physical address */
        if (RT_FAILURE(rc))
        {
            LogRel((DBGFLOG_NAME ": Elf64WriteProgHdr failed for memory range(%u) cbFileRange=%u cbMemRange=%u rc=%Rrc\n",
                    iRange, cbFileRange, cbMemRange, rc));
            return rc;
        }

        offMemRange += cbFileRange;
    }

    /*
     * Write the Core descriptor note header and data.
     */
    Assert(RTFileTell(hFile) == offCoreDescriptor);
    rc = Elf64WriteNoteHdr(hFile, NT_VBOXCORE, g_pcszCoreVBoxCore, &CoreDescriptor, sizeof(CoreDescriptor));
    if (RT_FAILURE(rc))
    {
        LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr failed for Note '%s' rc=%Rrc\n", g_pcszCoreVBoxCore, rc));
        return rc;
    }

    /*
     * Write the CPU context note headers and data.
     */
    Assert(RTFileTell(hFile) == offCpuDumps);
    PDBGFCORECPU pDbgfCoreCpu = (PDBGFCORECPU)RTMemAlloc(sizeof(*pDbgfCoreCpu));
    if (RT_UNLIKELY(!pDbgfCoreCpu))
    {
        LogRel((DBGFLOG_NAME ": failed to alloc %u bytes for DBGFCORECPU\n", sizeof(*pDbgfCoreCpu)));
        return VERR_NO_MEMORY;
    }

    for (uint32_t iCpu = 0; iCpu < pVM->cCpus; iCpu++)
    {
        PVMCPU      pVCpu = &pVM->aCpus[iCpu];
        PCPUMCTX    pCtx  = CPUMQueryGuestCtxPtr(pVCpu);
        if (RT_UNLIKELY(!pCtx))
        {
            LogRel((DBGFLOG_NAME ": CPUMQueryGuestCtxPtr failed for vCPU[%u]\n", iCpu));
            RTMemFree(pDbgfCoreCpu);
            return VERR_INVALID_POINTER;
        }

        RT_BZERO(pDbgfCoreCpu, sizeof(*pDbgfCoreCpu));
        dbgfR3GetCoreCpu(pCtx, pDbgfCoreCpu);
        rc = Elf64WriteNoteHdr(hFile, NT_VBOXCPU, g_pcszCoreVBoxCpu, pDbgfCoreCpu, sizeof(*pDbgfCoreCpu));
        if (RT_FAILURE(rc))
        {
            LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr failed for vCPU[%u] rc=%Rrc\n", iCpu, rc));
            RTMemFree(pDbgfCoreCpu);
            return rc;
        }
    }
    RTMemFree(pDbgfCoreCpu);
    pDbgfCoreCpu = NULL;

    /*
     * Write memory ranges.
     */
    Assert(RTFileTell(hFile) == offMemory);
    for (uint16_t iRange = 0; iRange < cMemRanges; iRange++)
    {
        RTGCPHYS GCPhysStart;
        RTGCPHYS GCPhysEnd;
        bool     fIsMmio;
        rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, &fIsMmio);
        if (RT_FAILURE(rc))
        {
            LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange(2) failed for iRange(%u) rc=%Rrc\n", iRange, rc));
            return rc;
        }

        if (fIsMmio)
            continue;

        /*
         * Write page-by-page of this memory range.
         *
         * The read function may fail on MMIO ranges, we write these as zero
         * pages for now (would be nice to have the VGA bits there though).
         */
        uint64_t cbMemRange  = GCPhysEnd - GCPhysStart + 1;
        uint64_t cPages      = cbMemRange >> PAGE_SHIFT;
        for (uint64_t iPage = 0; iPage < cPages; iPage++)
        {
            uint8_t abPage[PAGE_SIZE];
            rc = PGMPhysSimpleReadGCPhys(pVM, abPage, GCPhysStart + (iPage << PAGE_SHIFT),  sizeof(abPage));
            if (RT_FAILURE(rc))
            {
                if (rc != VERR_PGM_PHYS_PAGE_RESERVED)
                    LogRel((DBGFLOG_NAME ": PGMPhysRead failed for iRange=%u iPage=%u. rc=%Rrc. Ignoring...\n", iRange, iPage, rc));
                RT_ZERO(abPage);
            }

            rc = RTFileWrite(hFile, abPage, sizeof(abPage), NULL /* all */);
            if (RT_FAILURE(rc))
            {
                LogRel((DBGFLOG_NAME ": RTFileWrite failed. iRange=%u iPage=%u rc=%Rrc\n", iRange, iPage, rc));
                return rc;
            }
        }
    }

    return rc;
}