VirtualBox

Changeset 75320 in vbox


Ignore:
Timestamp:
Nov 8, 2018 12:16:27 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
126436
Message:

VMM/IEM: Nested VMX: bugref:9180 Added APIC memory access VM-exits. Might be more places to cover.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/cpum.h

    r74834 r75320  
    19621962}
    19631963
     1964
     1965/**
     1966 * Returns the guest-physical address of the APIC-access page when executing a
     1967 * nested-guest.
     1968 *
     1969 * @returns The APIC-access page guest-physical address.
     1970 * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
     1971 * @param   pCtx        Pointer to the context.
     1972 */
     1973DECLINLINE(uint64_t) CPUMGetGuestVmxApicAccessPageAddr(PVMCPU pVCpu, PCCPUMCTX pCtx)
     1974{
     1975    RT_NOREF(pVCpu);
     1976    Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX);
     1977    Assert(pCtx->hwvirt.vmx.fInVmxNonRootMode);
     1978    Assert(pCtx->hwvirt.vmx.CTX_SUFF(pVmcs));
     1979    return pCtx->hwvirt.vmx.CTX_SUFF(pVmcs)->u64AddrApicAccess.u;
     1980}
     1981
    19641982# endif /* !IN_RC */
    19651983
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r75201 r75320  
    447447    do { return iemVmxVmexitTripleFault(a_pVCpu); } while (0)
    448448
     449# define IEM_VMX_VMEXIT_APIC_ACCESS_RET(a_pVCpu, a_offAccess, a_fAccess) \
     450    do { return iemVmxVmexitApicAccess((a_pVCpu), (a_offAccess), (a_fAccess)); } while (0)
     451
    449452#else
    450453# define IEM_VMX_IS_ROOT_MODE(a_pVCpu)                                          (false)
     
    458461# define IEM_VMX_VMEXIT_MWAIT_RET(a_pVCpu, a_fMonitorArmed, a_cbInstr)          do { return VERR_VMX_IPE_1; } while (0)
    459462# define IEM_VMX_VMEXIT_TRIPLE_FAULT_RET(a_pVCpu)                               do { return VERR_VMX_IPE_1; } while (0)
     463# define IEM_VMX_VMEXIT_APIC_ACCESS_RET(a_pVCpu, a_offAccess, a_fAccess)        do { return VERR_VMX_IPE_1; } while (0)
    460464
    461465#endif
     
    976980#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    977981IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTaskSwitch(PVMCPU pVCpu, IEMTASKSWITCH enmTaskSwitch, RTSEL SelNewTss, uint8_t cbInstr);
    978 IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2,
    979                                               uint8_t cbInstr);
     982IEM_STATIC VBOXSTRICTRC     iemVmxVmexitEvent(PVMCPU pVCpu, uint8_t uVector, uint32_t fFlags, uint32_t uErrCode, uint64_t uCr2, uint8_t cbInstr);
    980983IEM_STATIC VBOXSTRICTRC     iemVmxVmexitTripleFault(PVMCPU pVCpu);
    981984IEM_STATIC VBOXSTRICTRC     iemVmxVmexitPreemptTimer(PVMCPU pVCpu);
     
    984987IEM_STATIC VBOXSTRICTRC     iemVmxVmexitInitIpi(PVMCPU pVCpu);
    985988IEM_STATIC VBOXSTRICTRC     iemVmxVmexitIntWindow(PVMCPU pVCpu);
     989IEM_STATIC VBOXSTRICTRC     iemVmxVirtApicAccessMem(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData, uint32_t fAccess);
     990IEM_STATIC VBOXSTRICTRC     iemVmxVmexitApicAccess(PVMCPU pVCpu, uint16_t offAccess, uint32_t fAccess);
    986991#endif
    987992
    988993#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
    989994IEM_STATIC VBOXSTRICTRC     iemSvmVmexit(PVMCPU pVCpu, uint64_t uExitCode, uint64_t uExitInfo1, uint64_t uExitInfo2);
    990 IEM_STATIC VBOXSTRICTRC     iemHandleSvmEventIntercept(PVMCPU pVCpu, uint8_t u8Vector, uint32_t fFlags, uint32_t uErr,
    991                                                        uint64_t uCr2);
     995IEM_STATIC VBOXSTRICTRC     iemHandleSvmEventIntercept(PVMCPU pVCpu, uint8_t u8Vector, uint32_t fFlags, uint32_t uErr, uint64_t uCr2);
    992996#endif
    993997
     
    85988602        return rcStrict;
    85998603    GCPhysSecond &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8604
     8605#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     8606    /*
     8607     * Check if we need to cause an APIC-access VM-exit.
     8608     *
     8609     * The reason we do have to check whether the access is to be virtualized here is that
     8610     * we already know we're crossing a page-boundary. Any cross-page access (which is at
     8611     * most 4 bytes) involves accessing offsets prior to XAPIC_OFF_ID or extends well beyond
     8612     * XAPIC_OFF_END + 4 bytes of the APIC-access page and hence must cause a VM-exit.
     8613     */
     8614    if (   CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu))
     8615        && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
     8616    {
     8617        RTGCPHYS const GCPhysMemFirst  = GCPhysFirst  & ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8618        RTGCPHYS const GCPhysMemSecond = GCPhysSecond & ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8619        RTGCPHYS const GCPhysApicAccessBase = CPUMGetGuestVmxApicAccessPageAddr(pVCpu, IEM_GET_CTX(pVCpu))
     8620                                            & ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8621        if (   GCPhysMemFirst  == GCPhysApicAccessBase
     8622            || GCPhysMemSecond == GCPhysApicAccessBase)
     8623        {
     8624            uint16_t const offAccess = GCPhysFirst & (RTGCPHYS)PAGE_OFFSET_MASK;
     8625            IEM_VMX_VMEXIT_APIC_ACCESS_RET(pVCpu, offAccess, fAccess);
     8626        }
     8627    }
     8628#endif
    86008629
    86018630    PVM pVM = pVCpu->CTX_SUFF(pVM);
     
    88798908    iemMemUpdateWrittenCounter(pVCpu, fAccess, cbMem);
    88808909    *ppvMem = pvMem;
     8910
     8911#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
     8912    /*
     8913     * Check if this is an APIC-access and whether it needs to be virtualized.
     8914     */
     8915    if (   CPUMIsGuestInVmxNonRootMode(IEM_GET_CTX(pVCpu))
     8916        && IEM_VMX_IS_PROCCTLS2_SET(pVCpu, VMX_PROC_CTLS2_VIRT_APIC_ACCESS))
     8917    {
     8918        RTGCPHYS const GCPhysMemAccessBase  = GCPhysFirst & ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8919        RTGCPHYS const GCPhysApicAccessBase = CPUMGetGuestVmxApicAccessPageAddr(pVCpu, IEM_GET_CTX(pVCpu))
     8920                                            & ~(RTGCPHYS)PAGE_OFFSET_MASK;
     8921        if (GCPhysMemAccessBase == GCPhysApicAccessBase)
     8922        {
     8923            Assert(pvMem);
     8924            uint16_t const offAccess = GCPhysFirst & (RTGCPHYS)PAGE_OFFSET_MASK;
     8925            return iemVmxVirtApicAccessMem(pVCpu, offAccess, cbMem, pvMem, fAccess);
     8926        }
     8927    }
     8928#endif
     8929
    88818930    return VINF_SUCCESS;
    88828931}
     
    1389413943                      /* nested hw.virt codes: */
    1389513944                      || rcStrict == VINF_VMX_VMEXIT
     13945                      || rcStrict == VINF_VMX_MODIFIES_BEHAVIOR
    1389613946                      || rcStrict == VINF_SVM_VMEXIT
    1389713947                      , ("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
     
    1389913949            int32_t const rcPassUp = pVCpu->iem.s.rcPassUp;
    1390013950#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
    13901             if (   rcStrict == VINF_VMX_VMEXIT
     13951            if (   (   rcStrict == VINF_VMX_VMEXIT
     13952                    || rcStrict == VINF_VMX_MODIFIES_BEHAVIOR)
    1390213953                && rcPassUp == VINF_SUCCESS)
    1390313954                rcStrict = VINF_SUCCESS;
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h

    r75316 r75320  
    40004000 *                      IEM_ACCESS_TYPE_WRITE).
    40014001 */
    4002 IEM_STATIC bool iemVmxVirtApicIsAccessIntercepted(PVMCPU pVCpu, uint16_t offAccess, uint32_t cbAccess, uint32_t fAccess)
     4002IEM_STATIC bool iemVmxVirtApicIsAccessIntercepted(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, uint32_t fAccess)
    40034003{
    40044004    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     
    40294029
    40304030    /*
    4031      * Check read accesses to the APIC-access page that cause VM-exits.
    4032      */
    4033     if (fAccess == IEM_ACCESS_TYPE_READ)
    4034     {
     4031     * Check write accesses to the APIC-access page that cause VM-exits.
     4032     */
     4033    if (fAccess & IEM_ACCESS_TYPE_WRITE)
     4034    {
     4035        if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
     4036        {
     4037            /*
     4038             * With APIC-register virtualization, a write access to any of the
     4039             * following registers are virtualized. Accessing any other register
     4040             * causes a VM-exit.
     4041             */
     4042            uint16_t const offAlignedAccess = offAccess & 0xfffc;
     4043            switch (offAlignedAccess)
     4044            {
     4045                case XAPIC_OFF_ID:
     4046                case XAPIC_OFF_TPR:
     4047                case XAPIC_OFF_EOI:
     4048                case XAPIC_OFF_LDR:
     4049                case XAPIC_OFF_DFR:
     4050                case XAPIC_OFF_SVR:
     4051                case XAPIC_OFF_ESR:
     4052                case XAPIC_OFF_ICR_LO:
     4053                case XAPIC_OFF_ICR_HI:
     4054                case XAPIC_OFF_LVT_TIMER:
     4055                case XAPIC_OFF_LVT_THERMAL:
     4056                case XAPIC_OFF_LVT_PERF:
     4057                case XAPIC_OFF_LVT_LINT0:
     4058                case XAPIC_OFF_LVT_LINT1:
     4059                case XAPIC_OFF_LVT_ERROR:
     4060                case XAPIC_OFF_TIMER_ICR:
     4061                case XAPIC_OFF_TIMER_DCR:
     4062                    break;
     4063                default:
     4064                    return true;
     4065            }
     4066        }
     4067        else if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
     4068        {
     4069            /*
     4070             * With virtual-interrupt delivery, a write access to any of the
     4071             * following registers are virtualized. Accessing any other register
     4072             * causes a VM-exit.
     4073             *
     4074             * Note! The specification does not allow writing to offsets in-between
     4075             * these registers (e.g. TPR + 1 byte) unlike read accesses.
     4076             */
     4077            switch (offAccess)
     4078            {
     4079                case XAPIC_OFF_TPR:
     4080                case XAPIC_OFF_EOI:
     4081                case XAPIC_OFF_ICR_LO:
     4082                    break;
     4083                default:
     4084                    return true;
     4085            }
     4086        }
     4087        else
     4088        {
     4089            /*
     4090             * Without APIC-register virtualization or virtual-interrupt delivery,
     4091             * only TPR accesses are virtualized.
     4092             */
     4093            if (offAccess == XAPIC_OFF_TPR)
     4094            { /* likely */ }
     4095            else
     4096                return true;
     4097        }
     4098    }
     4099    else
     4100    {
     4101        /*
     4102         * Check read accesses to the APIC-access page that cause VM-exits.
     4103         */
    40354104        if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
    40364105        {
     
    40824151        }
    40834152    }
    4084     else
    4085     {
    4086         /*
    4087          * Check write accesses to the APIC-access page that cause VM-exits.
    4088          */
    4089         if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT)
    4090         {
    4091             /*
    4092              * With APIC-register virtualization, a write access to any of the
    4093              * following registers are virtualized. Accessing any other register
    4094              * causes a VM-exit.
    4095              */
    4096             uint16_t const offAlignedAccess = offAccess & 0xfffc;
    4097             switch (offAlignedAccess)
    4098             {
    4099                 case XAPIC_OFF_ID:
    4100                 case XAPIC_OFF_TPR:
    4101                 case XAPIC_OFF_EOI:
    4102                 case XAPIC_OFF_LDR:
    4103                 case XAPIC_OFF_DFR:
    4104                 case XAPIC_OFF_SVR:
    4105                 case XAPIC_OFF_ESR:
    4106                 case XAPIC_OFF_ICR_LO:
    4107                 case XAPIC_OFF_ICR_HI:
    4108                 case XAPIC_OFF_LVT_TIMER:
    4109                 case XAPIC_OFF_LVT_THERMAL:
    4110                 case XAPIC_OFF_LVT_PERF:
    4111                 case XAPIC_OFF_LVT_LINT0:
    4112                 case XAPIC_OFF_LVT_LINT1:
    4113                 case XAPIC_OFF_LVT_ERROR:
    4114                 case XAPIC_OFF_TIMER_ICR:
    4115                 case XAPIC_OFF_TIMER_DCR:
    4116                     break;
    4117                 default:
    4118                     return true;
    4119             }
    4120         }
    4121         else if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
    4122         {
    4123             /*
    4124              * With virtual-interrupt delivery, a write access to any of the
    4125              * following registers are virtualized. Accessing any other register
    4126              * causes a VM-exit.
    4127              *
    4128              * Note! The specification does not allow writing to offsets in-between
    4129              * these registers (e.g. TPR + 1 byte) unlike read accesses.
    4130              */
    4131             switch (offAccess)
    4132             {
    4133                 case XAPIC_OFF_TPR:
    4134                 case XAPIC_OFF_EOI:
    4135                 case XAPIC_OFF_ICR_LO:
    4136                     break;
    4137                 default:
    4138                     return true;
    4139             }
    4140         }
    4141         else
    4142         {
    4143             /*
    4144              * Without APIC-register virtualization or virtual-interrupt delivery,
    4145              * only TPR accesses are virtualized.
    4146              */
    4147             if (offAccess == XAPIC_OFF_TPR)
    4148             { /* likely */ }
    4149             else
    4150                 return true;
    4151         }
    4152     }
    41534153
    41544154    /* The APIC-access is virtualized, does not cause a VM-exit. */
     
    41744174 * @param   pVCpu       The cross context virtual CPU structure.
    41754175 * @param   offAccess   The offset of the register being accessed.
    4176  * @param   fAccess     The type of access (must be IEM_ACCESS_TYPE_READ or
    4177  *                      IEM_ACCESS_TYPE_WRITE).
     4176 * @param   fAccess     The type of access (must contain IEM_ACCESS_TYPE_READ or
     4177 *                      IEM_ACCESS_TYPE_WRITE or IEM_ACCESS_INSTRUCTION).
    41784178 */
    41794179IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicAccess(PVMCPU pVCpu, uint16_t offAccess, uint32_t fAccess)
    41804180{
    4181     Assert(fAccess == IEM_ACCESS_TYPE_READ || fAccess == IEM_ACCESS_TYPE_WRITE);
     4181    Assert((fAccess & IEM_ACCESS_TYPE_READ) || (fAccess & IEM_ACCESS_TYPE_WRITE) || (fAccess & IEM_ACCESS_INSTRUCTION));
    41824182
    41834183    VMXAPICACCESS enmAccess;
     
    41854185    if (fInEventDelivery)
    41864186        enmAccess = VMXAPICACCESS_LINEAR_EVENT_DELIVERY;
    4187     else if (fAccess == IEM_ACCESS_TYPE_READ)
    4188         enmAccess = VMXAPICACCESS_LINEAR_READ;
     4187    else if (fAccess & IEM_ACCESS_INSTRUCTION)
     4188        enmAccess = VMXAPICACCESS_LINEAR_INSTR_FETCH;
     4189    else if (fAccess & IEM_ACCESS_TYPE_WRITE)
     4190        enmAccess = VMXAPICACCESS_LINEAR_WRITE;
    41894191    else
    41904192        enmAccess = VMXAPICACCESS_LINEAR_WRITE;
     
    41984200
    41994201/**
    4200  * Virtualizes an APIC read access.
     4202 * Virtualizes a memory-based APIC-access.
    42014203 *
    42024204 * @returns VBox strict status code.
    42034205 * @param   pVCpu       The cross context virtual CPU structure.
    4204  * @param   offAccess   The offset of the register being read.
    4205  * @param   cbAccess    The size of the APIC access.
    4206  * @param   pvData      Where to store the read data.
    4207  */
    4208 IEM_STATIC VBOXSTRICTRC iemVmxVirtApicRead(PVMCPU pVCpu, uint16_t offAccess, uint32_t cbAccess, void *pvData)
     4206 * @param   offAccess   The offset of the register being accessed (within the
     4207 *                      APIC-access page).
     4208 * @param   cbAccess    The size of the access in bytes.
     4209 * @param   pvData      Pointer to the data being read or written.
     4210 * @param   fAccess     The type of access (must contain IEM_ACCESS_TYPE_READ or
     4211 *                      IEM_ACCESS_TYPE_WRITE or IEM_ACCESS_INSTRUCTION).
     4212 */
     4213IEM_STATIC VBOXSTRICTRC iemVmxVirtApicAccessMem(PVMCPU pVCpu, uint16_t offAccess, size_t cbAccess, void *pvData,
     4214                                                uint32_t fAccess)
    42094215{
    42104216    PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
     
    42124218    Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
    42134219    Assert(pvData);
    4214 
    4215     /* Check if we need to cause a VM-exit for this APIC access. */
    4216     bool const fIntercept = iemVmxVirtApicIsAccessIntercepted(pVCpu, offAccess, cbAccess, IEM_ACCESS_TYPE_READ);
     4220    Assert(   (fAccess & IEM_ACCESS_TYPE_READ)
     4221           || (fAccess & IEM_ACCESS_TYPE_WRITE)
     4222           || (fAccess & IEM_ACCESS_INSTRUCTION));
     4223
     4224    bool const fIntercept = iemVmxVirtApicIsAccessIntercepted(pVCpu, offAccess, cbAccess, fAccess);
    42174225    if (fIntercept)
    4218         return iemVmxVmexitApicAccess(pVCpu, offAccess, IEM_ACCESS_TYPE_READ);
    4219 
    4220     /*
    4221      * A read access from the APIC-access page that is virtualized (rather than
    4222      * causing a VM-exit) returns data from the virtual-APIC page.
    4223      *
    4224      * See Intel spec. 29.4.2 "Virtualizing Reads from the APIC-Access Page".
    4225      */
    4226     Assert(cbAccess <= 4);
    4227     Assert(offAccess < XAPIC_OFF_END + 4);
    4228     static uint32_t const s_auAccessSizeMasks[] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
    4229 
    4230     uint32_t u32Data = iemVmxVirtApicReadRaw32(pVCpu, offAccess);
    4231     u32Data &= s_auAccessSizeMasks[cbAccess];
    4232     *(uint32_t *)pvData = u32Data;
    4233     return VINF_VMX_INTERCEPT_NOT_ACTIVE;
    4234 }
    4235 
    4236 
    4237 /**
    4238  * Virtualizes an APIC write access.
    4239  *
    4240  * @returns VBox strict status code.
    4241  * @param   pVCpu       The cross context virtual CPU structure.
    4242  * @param   offAccess   The offset of the register being written.
    4243  * @param   cbAccess    The size of the APIC access.
    4244  * @param   pvData      Pointer to the data being written.
    4245  */
    4246 IEM_STATIC VBOXSTRICTRC iemVmxVirtApicWrite(PVMCPU pVCpu, uint16_t offAccess, uint32_t cbAccess, void *pvData)
    4247 {
    4248     PCVMXVVMCS pVmcs = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
    4249     Assert(pVmcs);
    4250     Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_APIC_ACCESS);
    4251     Assert(pvData);
    4252 
    4253     /* Check if we need to cause a VM-exit for this APIC access. */
    4254     bool const fIntercept = iemVmxVirtApicIsAccessIntercepted(pVCpu, offAccess, cbAccess, IEM_ACCESS_TYPE_WRITE);
    4255     if (fIntercept)
    4256         return iemVmxVmexitApicAccess(pVCpu, offAccess, IEM_ACCESS_TYPE_WRITE);
    4257 
    4258     /*
    4259      * A write access to the APIC-access page that is virtualized (rather than
    4260      * causing a VM-exit) writes data to the virtual-APIC page.
    4261      */
    4262     uint32_t const u32Data = *(uint32_t *)pvData;
    4263     iemVmxVirtApicWriteRaw32(pVCpu, offAccess, u32Data);
    4264 
    4265     /*
    4266      * Record the currently updated APIC offset, as we need this later for figuring
    4267      * out what to do as well as the exit qualification when causing an APIC-write VM-exit.
    4268      */
    4269     pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = offAccess;
    4270 
    4271     /*
    4272      * After completion of the current operation, we need to perform TPR virtualization,
    4273      * EOI virtualization or APIC-write VM-exit depending on which register was written.
    4274      *
    4275      * The current operation may be a REP-prefixed string instruction, execution of any
    4276      * other instruction, or delivery of an event through the IDT.
    4277      *
    4278      * Thus things like clearing bytes 3:1 of the VTPR, clearing VEOI are not to be
    4279      * performed now but later after completion of the current operation.
    4280      *
    4281      * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
    4282      */
    4283     VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC);
    4284     return VINF_VMX_INTERCEPT_NOT_ACTIVE;
     4226        return iemVmxVmexitApicAccess(pVCpu, offAccess, fAccess);
     4227
     4228    if (fAccess & IEM_ACCESS_TYPE_WRITE)
     4229    {
     4230        /*
     4231         * Record the currently updated APIC offset, as we need this later for figuring
     4232         * out what to do as well as the exit qualification when causing an APIC-write VM-exit.
     4233         */
     4234        pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = offAccess;
     4235
     4236        /*
     4237         * A write access to the APIC-access page that is virtualized (rather than
     4238         * causing a VM-exit) writes data to the virtual-APIC page.
     4239         */
     4240        uint32_t const u32Data = *(uint32_t *)pvData;
     4241        iemVmxVirtApicWriteRaw32(pVCpu, offAccess, u32Data);
     4242
     4243        /*
     4244         * After completion of the current operation, we need to perform TPR virtualization,
     4245         * EOI virtualization or APIC-write VM-exit depending on which register was written.
     4246         *
     4247         * The current operation may be a REP-prefixed string instruction, execution of any
     4248         * other instruction, or delivery of an event through the IDT.
     4249         *
     4250         * Thus things like clearing bytes 3:1 of the VTPR, clearing VEOI are not to be
     4251         * performed now but later after completion of the current operation.
     4252         *
     4253         * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
     4254         */
     4255        VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC);
     4256    }
     4257    else
     4258    {
     4259        /*
     4260         * A read access from the APIC-access page that is virtualized (rather than
     4261         * causing a VM-exit) returns data from the virtual-APIC page.
     4262         *
     4263         * See Intel spec. 29.4.2 "Virtualizing Reads from the APIC-Access Page".
     4264         */
     4265        Assert(cbAccess <= 4);
     4266        Assert(offAccess < XAPIC_OFF_END + 4);
     4267        static uint32_t const s_auAccessSizeMasks[] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
     4268
     4269        uint32_t u32Data = iemVmxVirtApicReadRaw32(pVCpu, offAccess);
     4270        u32Data &= s_auAccessSizeMasks[cbAccess];
     4271        *(uint32_t *)pvData = u32Data;
     4272    }
     4273
     4274    return VINF_VMX_MODIFIES_BEHAVIOR;
    42854275}
    42864276
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