VirtualBox

Changeset 5396 in vbox for trunk/src


Ignore:
Timestamp:
Oct 21, 2007 3:57:23 AM (17 years ago)
Author:
vboxsync
Message:

Shaved off a few ticks on RDTSC emulation to speed up Solaris guest.

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

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

    r5395 r5396  
    518518    STAM_REG(pVM, &pVM->trpm.s.StatForwardProfHC,       STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/Prof/HC",         STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
    519519
    520     STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm,        STAMTYPE_PROFILE_ADV, "/TRPM/Trap0d/Prof/Disasm",         STAMUNIT_TICKS_PER_CALL, "Profiling trpmGCTrap0dHandler.");
    521     STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRing0RdTsc,    STAMTYPE_COUNTER, "/TRPM/Trap0d/RdTsc-R0",                    STAMUNIT_OCCURENCES, "Number of RDTSC #GPs from guest ring-0.");
    522     STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRing3RdTsc,    STAMTYPE_COUNTER, "/TRPM/Trap0d/RdTsc-R3",                    STAMUNIT_OCCURENCES, "Number of RDTSC #GPs from guest ring-3.");
     520    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm,        STAMTYPE_PROFILE, "/TRPM/GC/Traps/0d/Disasm",              STAMUNIT_TICKS_PER_CALL, "Profiling disassembly part of trpmGCTrap0dHandler.");
     521    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRdTsc,         STAMTYPE_COUNTER, "/TRPM/GC/Traps/0d/RdTsc",                   STAMUNIT_OCCURENCES, "Number of RDTSC #GPs.");
    523522
    524523    /*
  • trunk/src/VBox/VMM/TRPMInternal.h

    r5395 r5396  
    174174    STAMPROFILEADV  StatForwardProfGC;
    175175    STAMPROFILEADV  StatForwardProfHC;
    176     STAMPROFILEADV  StatTrap0dDisasm;
    177     STAMCOUNTER     StatTrap0dRing0RdTsc;   /**< Number of RDTSC #GPs from guest ring-0. */
    178     STAMCOUNTER     StatTrap0dRing3RdTsc;   /**< Number of RDTSC #GPs from guest ring-3. */
     176    STAMPROFILE     StatTrap0dDisasm;
     177    STAMCOUNTER     StatTrap0dRdTsc;        /**< Number of RDTSC #GPs. */
    179178
    180179    /* R3: Statistics for interrupt handlers (allocated on the hypervisor heap). */
  • trunk/src/VBox/VMM/TRPMInternal.mac

    r5395 r5396  
    6363    .StatForwardProfGC        resb STAMPROFILEADV_size
    6464    .StatForwardProfHC        resb STAMPROFILEADV_size
    65     .StatTrap0dDisasm         resb STAMPROFILEADV_size
    66     .StatTrap0dRing0RdTsc     resb STAMCOUNTER_size
    67     .StatTrap0dRing3RdTsc     resb STAMCOUNTER_size
     65    .StatTrap0dDisasm         resb STAMPROFILE_size
     66    .StatTrap0dRdTsc          resb STAMCOUNTER_size
    6867
    6968    .paStatForwardedIRQR3  RTR3PTR_RES 1
  • trunk/src/VBox/VMM/VMMAll/SELMAll.cpp

    r4776 r5396  
    321321
    322322/**
    323  * Validates and converts a GC selector based code address to a flat address.
    324  *
    325  * @returns Flat address.
     323 * Validates and converts a GC selector based code address to a flat
     324 * address when in real or v8086 mode.
     325 *
     326 * @returns VINF_SUCCESS.
     327 * @param   pVM     VM Handle.
     328 * @param   SelCS   Selector part.
     329 * @param   pHidCS  The hidden CS register part. Optional.
     330 * @param   Addr    Address part.
     331 * @param   ppvFlat Where to store the flat address.
     332 */
     333DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVM pVM, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
     334{
     335    RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
     336    if (!pHidCS || !CPUMAreHiddenSelRegsValid(pVM))
     337        uFlat += ((RTGCUINTPTR)SelCS << 4);
     338    else
     339        uFlat += pHidCS->u32Base;
     340    *ppvFlat = (RTGCPTR)uFlat;
     341    return VINF_SUCCESS;
     342}
     343
     344
     345/**
     346 * Validates and converts a GC selector based code address to a flat
     347 * address when in protected/long mode using the standard algorithm.
     348 *
     349 * @returns VBox status code.
    326350 * @param   pVM     VM Handle.
    327351 * @param   SelCPL  Current privilege level. Get this from SS - CS might be conforming!
     
    330354 * @param   Addr    Address part.
    331355 * @param   ppvFlat Where to store the flat address.
    332  */
    333 static int selmValidateAndConvertCSAddr(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
     356 * @param   pcBits  Where to store the segment bitness (16/32/64). Optional.
     357 */
     358DECLINLINE(int) selmValidateAndConvertCSAddrStd(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
    334359{
    335360    Assert(!CPUMAreHiddenSelRegsValid(pVM));
     
    378403                if ((RTGCUINTPTR)Addr <= u32Limit)
    379404                {
    380                     if (ppvFlat)
    381                         *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr
    382                                                + (   (Desc.Gen.u8BaseHigh2 << 24)
    383                                                   |  (Desc.Gen.u8BaseHigh1 << 16)
    384                                                   |   Desc.Gen.u16BaseLow)
    385                                                  );
     405                    *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr
     406                                           + (   (Desc.Gen.u8BaseHigh2 << 24)
     407                                              |  (Desc.Gen.u8BaseHigh1 << 16)
     408                                              |   Desc.Gen.u16BaseLow)
     409                                             );
     410                    if (pcBits)
     411                        *pcBits = Desc.Gen.u1DefBig ? 32 : 16; /** @todo GUEST64 */
    386412                    return VINF_SUCCESS;
    387413                }
     
    397423
    398424/**
     425 * Validates and converts a GC selector based code address to a flat
     426 * address when in protected/long mode using the standard algorithm.
     427 *
     428 * @returns VBox status code.
     429 * @param   pVM     VM Handle.
     430 * @param   SelCPL  Current privilege level. Get this from SS - CS might be conforming!
     431 *                  A full selector can be passed, we'll only use the RPL part.
     432 * @param   SelCS   Selector part.
     433 * @param   Addr    Address part.
     434 * @param   ppvFlat Where to store the flat address.
     435 * @param   pcBits  Where to store the segment bitness (16/32/64). Optional.
     436 */
     437DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVM pVM, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
     438{
     439    /*
     440     * Check if present.
     441     */
     442    if (pHidCS->Attr.n.u1Present)
     443    {
     444        /*
     445         * Type check.
     446         */
     447        if (     pHidCS->Attr.n.u1DescType == 1
     448            &&  (pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
     449        {
     450            /*
     451             * Check level.
     452             */
     453            unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
     454            if (    !(pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CONF)
     455                ?   uLevel <= pHidCS->Attr.n.u2Dpl
     456                :   uLevel >= pHidCS->Attr.n.u2Dpl /* hope I got this right now... */
     457                    )
     458            {
     459                /*
     460                 * Limit check.
     461                 */
     462                uint32_t    u32Limit = pHidCS->u32Limit;
     463                /** @todo correct with hidden limit value?? */
     464                if (pHidCS->Attr.n.u1Granularity)
     465                    u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
     466                if ((RTGCUINTPTR)Addr <= u32Limit)
     467                {
     468                    *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr + pHidCS->u32Base );
     469                    return VINF_SUCCESS;
     470                }
     471                return VERR_OUT_OF_SELECTOR_BOUNDS;
     472            }
     473            return VERR_INVALID_RPL;
     474        }
     475        return VERR_NOT_CODE_SELECTOR;
     476    }
     477    return VERR_SELECTOR_NOT_PRESENT;
     478}
     479
     480
     481/**
    399482 * Validates and converts a GC selector based code address to a flat address.
    400483 *
    401  * @returns Flat address.
     484 * This is like SELMValidateAndConvertCSAddr + SELMIsSelector32Bit but with
     485 * invalid hidden CS data. It's customized for dealing efficiently with CS
     486 * at GC trap time.
     487 *
     488 * @returns VBox status code.
     489 * @param   pVM          VM Handle.
     490 * @param   eflags       Current eflags
     491 * @param   SelCPL       Current privilege level. Get this from SS - CS might be conforming!
     492 *                       A full selector can be passed, we'll only use the RPL part.
     493 * @param   SelCS        Selector part.
     494 * @param   Addr         Address part.
     495 * @param   ppvFlat      Where to store the flat address.
     496 * @param   pcBits       Where to store the 64-bit/32-bit/16-bit indicator.
     497 */
     498SELMDECL(int) SELMValidateAndConvertCSAddrGCTrap(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
     499{
     500    if (    CPUMIsGuestInRealMode(pVM)
     501        ||  eflags.Bits.u1VM)
     502    {
     503        *pcBits = 16;
     504        return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, NULL, Addr, ppvFlat);
     505    }
     506    return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, pcBits);
     507}
     508
     509
     510/**
     511 * Validates and converts a GC selector based code address to a flat address.
     512 *
     513 * @returns VBox status code.
    402514 * @param   pVM          VM Handle.
    403515 * @param   eflags       Current eflags
     
    411523SELMDECL(int) SELMValidateAndConvertCSAddr(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, CPUMSELREGHID *pHiddenCSSel, RTGCPTR Addr, PRTGCPTR ppvFlat)
    412524{
    413     /*
    414      * Deal with real & v86 mode first.
    415      */
    416525    if (    CPUMIsGuestInRealMode(pVM)
    417526        ||  eflags.Bits.u1VM)
    418     {
    419         if (ppvFlat)
    420         {
    421             RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
    422 
    423             if (!CPUMAreHiddenSelRegsValid(pVM))
    424                 uFlat += ((RTGCUINTPTR)SelCS << 4);
    425             else
    426                 uFlat += pHiddenCSSel->u32Base;
    427 
    428             *ppvFlat = (RTGCPTR)uFlat;
    429         }
    430         return VINF_SUCCESS;
    431     }
    432 
    433     /** @todo when we're in 16 bits mode, we should cut off the address as well.. */
    434 
     527        return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, pHiddenCSSel, Addr, ppvFlat);
     528
     529    /** @todo when we're in 16 bits mode, we should cut off the address as well? (like in selmValidateAndConvertCSAddrRealMode) */
    435530    if (!CPUMAreHiddenSelRegsValid(pVM))
    436         return selmValidateAndConvertCSAddr(pVM, SelCPL, SelCS, Addr, ppvFlat);
    437 
    438     /*
    439      * Check if present.
    440      */
    441     if (pHiddenCSSel->Attr.n.u1Present)
    442     {
    443         /*
    444          * Type check.
    445          */
    446         if (     pHiddenCSSel->Attr.n.u1DescType == 1
    447             &&  (pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
    448         {
    449             /*
    450              * Check level.
    451              */
    452             unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
    453             if (    !(pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CONF)
    454                 ?   uLevel <= pHiddenCSSel->Attr.n.u2Dpl
    455                 :   uLevel >= pHiddenCSSel->Attr.n.u2Dpl /* hope I got this right now... */
    456                     )
    457             {
    458                 /*
    459                  * Limit check.
    460                  */
    461                 uint32_t    u32Limit = pHiddenCSSel->u32Limit;
    462                 /** @todo correct with hidden limit value?? */
    463                 if (pHiddenCSSel->Attr.n.u1Granularity)
    464                     u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
    465                 if ((RTGCUINTPTR)Addr <= u32Limit)
    466                 {
    467                     if (ppvFlat)
    468                         *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr + pHiddenCSSel->u32Base );
    469 
    470                     return VINF_SUCCESS;
    471                 }
    472                 return VERR_OUT_OF_SELECTOR_BOUNDS;
    473             }
    474             return VERR_INVALID_RPL;
    475         }
    476         return VERR_NOT_CODE_SELECTOR;
    477     }
    478     return VERR_SELECTOR_NOT_PRESENT;
     531        return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, NULL);
     532    return selmValidateAndConvertCSAddrHidden(pVM, SelCPL, SelCS, pHiddenCSSel, Addr, ppvFlat);
    479533}
    480534
  • trunk/src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp

    r5395 r5396  
    525525    switch (pCpu->pCurInstr->opcode)
    526526    {
    527         /*
    528          * Since we're usually trapping RDTSC there may be a high volume
    529          * of these instructions. So, put it first and go straight to
    530          * the emulation function to save time.
    531          */
    532         case OP_RDTSC:
    533             STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRing0RdTsc);
    534             rc = EMInterpretRdtsc(pVM, pRegFrame);
    535             if (RT_SUCCESS(rc))
    536                 pRegFrame->eip += pCpu->opsize;
    537             else if (rc == VERR_EM_INTERPRETER)
    538                 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
    539             return trpmGCExitTrap(pVM, rc, pRegFrame);
    540 
    541527        case OP_INT3:
    542528            /*
     
    599585        case OP_LLDT:
    600586        case OP_STI:
     587        case OP_RDTSC:  /* just in case */
    601588        case OP_CLTS:
    602589        {
     
    675662
    676663        /*
    677          * Handle virtualized TSC reads.
    678          * Call the emulation function directly to skip unnecessary overhead.
     664         * Handle virtualized TSC reads, just in case.
    679665         */
    680666        case OP_RDTSC:
    681             STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRing3RdTsc);
    682             rc = EMInterpretRdtsc(pVM, pRegFrame);
    683             if (RT_SUCCESS(rc))
     667        {
     668            uint32_t cbIgnored;
     669            rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, PC, &cbIgnored);
     670            if (VBOX_SUCCESS(rc))
    684671                pRegFrame->eip += pCpu->opsize;
    685672            else if (rc == VERR_EM_INTERPRETER)
    686673                rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
    687674            return trpmGCExitTrap(pVM, rc, pRegFrame);
     675        }
    688676
    689677        /*
     
    712700
    713701/**
     702 * Emulates RDTSC for the \#GP handler.
     703 *
     704 * @returns VINF_SUCCESS or VINF_EM_RAW_EMULATE_INSTR.
     705 *
     706 * @param   pVM         Pointer to the shared VM structure.
     707 * @param   pRegFrame   Pointer to the registre frame for the trap.
     708 *                      This will be updated on successful return.
     709 */
     710DECLINLINE(int) trpmGCTrap0dHandlerRDTSC(PVM pVM, PCPUMCTXCORE pRegFrame)
     711{
     712    STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRdTsc);
     713
     714    if (CPUMGetGuestCR4(pVM) & X86_CR4_TSD)
     715        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); /* will trap (optimize later). */
     716
     717    uint64_t uTicks = TMCpuTickGet(pVM);
     718    pRegFrame->eax = uTicks;
     719    pRegFrame->edx = uTicks >> 32;
     720    pRegFrame->eip += 2;
     721    return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
     722}
     723
     724
     725/**
    714726 * \#GP (General Protection Fault) handler.
    715727 *
     
    726738    LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%VGv uErr=%RX32\n", pRegFrame->ss, pRegFrame->eip, pTrpm->uActiveErrorCode));
    727739
    728 #if 0 /* not right for iret. Shouldn't really be needed as SELMValidateAndConvertCSAddr deals with invalid cs. */
    729     /*
    730      * Filter out selector problems first as these may mean that the
    731      * instruction isn't safe to read. If we're here because CS is NIL
    732      * the flattening of cs:eip will deal with that.
    733      */
    734     if (    !(pTrpm->uActiveErrorCode & (X86_TRAP_ERR_IDT | X86_TRAP_ERR_EXTERNAL))
    735         &&  (pTrpm->uActiveErrorCode & X86_TRAP_ERR_SEL_MASK))
    736     {
    737         /* It's a guest trap. */
    738         return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
    739     }
    740 #endif
    741 
    742     STAM_PROFILE_ADV_START(&pVM->trpm.s.StatTrap0dDisasm, a);
    743     /*
    744      * Decode the instruction.
    745      */
     740    /*
     741     * Convert and validate CS.
     742     */
     743    STAM_PROFILE_START(&pVM->trpm.s.StatTrap0dDisasm, a);
    746744    RTGCPTR PC;
    747     int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
    748     if (VBOX_FAILURE(rc))
    749     {
    750         Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
     745    uint32_t cBits;
     746    int rc = SELMValidateAndConvertCSAddrGCTrap(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs,
     747                                                (RTGCPTR)pRegFrame->eip, &PC, &cBits);
     748    if (RT_FAILURE(rc))
     749    {
     750        Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n",
    751751             pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
    752         STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
     752        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
    753753        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
    754754    }
    755755
     756    /*
     757     * Optimize RDTSC traps.
     758     * Some guests (like Solaris) is using RDTSC all over the place and
     759     * will end up trapping a *lot* because of that.
     760     */
     761    if (   !pRegFrame->eflags.Bits.u1VM
     762        && ((uint8_t *)PC)[0] == 0x0f
     763        && ((uint8_t *)PC)[1] == 0x31)
     764    {
     765        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
     766        return trpmGCTrap0dHandlerRDTSC(pVM, pRegFrame);
     767    }
     768
     769    /*
     770     * Disassemble the instruction.
     771     */
    756772    DISCPUSTATE Cpu;
    757773    uint32_t    cbOp;
    758     rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
    759     if (VBOX_FAILURE(rc))
    760     {
    761         STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
     774    rc = DISCoreOneEx((RTGCUINTPTR)PC, cBits == 32 ? CPUMODE_32BIT : cBits == 16 ? CPUMODE_16BIT : CPUMODE_64BIT,
     775                      NULL, NULL, &Cpu, &cbOp);
     776    if (RT_FAILURE(rc))
     777    {
     778        AssertMsgFailed(("DISCoreOneEx failed to PC=%VGv rc=%Vrc\n", PC, rc));
     779        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
    762780        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
    763781    }
    764     STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
     782    STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
    765783
    766784    /*
     
    773791        return trpmGCExitTrap(pVM, rc, pRegFrame);
    774792    }
    775 
    776793
    777794    /*
     
    790807    /*
    791808     * Deal with v86 code.
    792      */
    793 
    794     /* We always set IOPL to zero which makes e.g. pushf fault in V86 mode. The guest might use IOPL=3 and therefor not expect a #GP.
    795      * Simply fall back to the recompiler to emulate this instruction.
    796      */
    797     /* Retrieve the eflags including the virtualized bits. */
    798     /** @note hackish as the cpumctxcore structure doesn't contain the right value */
     809     *
     810     * We always set IOPL to zero which makes e.g. pushf fault in V86
     811     * mode. The guest might use IOPL=3 and therefore not expect a #GP.
     812     * Simply fall back to the recompiler to emulate this instruction if
     813     * that's the case. To get the correct we must use CPUMRawGetEFlags.
     814     */
    799815    X86EFLAGS eflags;
    800     eflags.u32 = CPUMRawGetEFlags(pVM, pRegFrame);
     816    eflags.u32 = CPUMRawGetEFlags(pVM, pRegFrame); /* Get the correct value. */
    801817    if (eflags.Bits.u2IOPL != 3)
    802818    {
Note: See TracChangeset for help on using the changeset viewer.

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