Index: /trunk/include/VBox/vmm/iem.h
===================================================================
--- /trunk/include/VBox/vmm/iem.h	(revision 75619)
+++ /trunk/include/VBox/vmm/iem.h	(revision 75620)
@@ -329,5 +329,5 @@
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicAccessMsr(PVMCPU pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite);
-VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicUpdate(PVMCPU pVCpu);
+VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVirtApicWriteEmulation(PVMCPU pVCpu);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitPreemptTimer(PVMCPU pVCpu);
 VMM_INT_DECL(VBOXSTRICTRC)  IEMExecVmxVmexitExtInt(PVMCPU pVCpu, uint8_t uVector, bool fIntPending);
Index: /trunk/include/VBox/vmm/vm.h
===================================================================
--- /trunk/include/VBox/vmm/vm.h	(revision 75619)
+++ /trunk/include/VBox/vmm/vm.h	(revision 75620)
@@ -552,8 +552,8 @@
 /** The bit number for VMCPU_FF_VMX_MTF. */
 #define VMCPU_FF_VMX_MTF_BIT                33
-/** Virtual-APIC operation pending (VTPR, VEOI or APIC-write).  */
-#define VMCPU_FF_VMX_UPDATE_VAPIC           RT_BIT_64(VMCPU_FF_VMX_UPDATE_VAPIC_BIT)
+/** VMX APIC-write emulation pending.  */
+#define VMCPU_FF_VMX_APIC_WRITE             RT_BIT_64(VMCPU_FF_VMX_APIC_WRITE_BIT)
 /** The bit number for VMCPU_FF_VMX_UPDATE_VTPR. */
-#define VMCPU_FF_VMX_UPDATE_VAPIC_BIT       34
+#define VMCPU_FF_VMX_APIC_WRITE_BIT         34
 
 
Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75619)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 75620)
@@ -15715,30 +15715,15 @@
 
 /**
- * Interface for HM and EM to perform a post-instruction virtual-APIC update.
+ * Interface for HM and EM to perform a APIC-write emulation.
  *
  * @returns Strict VBox status code.
- * @retval  VINF_VMX_VMEXIT if the virtual-APIC update causes a VM-exit.
- * @retval  VINF_VMX_INTERCEPT_NOT_ACTIVE if no change was made.
- *
  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
  * @thread  EMT(pVCpu)
  */
-VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicUpdate(PVMCPU pVCpu)
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicWriteEmulation(PVMCPU pVCpu)
 {
     IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK);
 
-    /*
-     * Record the virtual-APIC offset which was just updated and clear
-     * the virtual-APIC update force-flag and process it now.
-     */
-    uint16_t const offApicWrite = iemVmxVirtApicClearPostAction(pVCpu);
-    VBOXSTRICTRC rcStrict;
-    switch (offApicWrite)
-    {
-        case XAPIC_OFF_TPR:         rcStrict = iemVmxTprVirtualization(pVCpu);      break;
-        case XAPIC_OFF_EOI:         rcStrict = iemVmxEoiVirtualization(pVCpu);      break;
-        case X2APIC_OFF_SELF_IPI:   rcStrict = iemVmxSelfIpiVirtualization(pVCpu);  break;
-        IEM_NOT_REACHED_DEFAULT_CASE_RET();
-    }
+    VBOXSTRICTRC rcStrict = iemVmxApicWriteEmulation(pVCpu);
     if (pVCpu->iem.s.cActiveMappings)
         iemMemRollback(pVCpu);
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 75619)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 75620)
@@ -5368,6 +5368,6 @@
                 if (IEM_VMX_IS_PROCCTLS_SET(pVCpu, VMX_PROC_CTLS_USE_TPR_SHADOW))
                 {
-                    uint32_t const uVTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
-                    crX = (uVTpr >> 4) & 0xf;
+                    uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
+                    crX = (uTpr >> 4) & 0xf;
                     break;
                 }
@@ -5905,9 +5905,13 @@
                  * cleared. Following this the processor performs TPR virtualization.
                  *
-                 * See Intel Spec. 29.3 "Virtualizing CR8-based TPR Accesses"
+                 * However, we should not perform TPR virtualization immediately here but
+                 * after this instruction has completed.
+                 *
+                 * See Intel spec. 29.3 "Virtualizing CR8-based TPR Accesses"
+                 * See Intel spec. 27.1 "Architectural State Before A VM-exit"
                  */
-                uint32_t const uVTpr = (uNewCrX & 0xf) << 4;
-                iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uVTpr);
-                iemVmxVirtApicSetPostAction(pVCpu, XAPIC_OFF_TPR);
+                uint32_t const uTpr = (uNewCrX & 0xf) << 4;
+                iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
+                iemVmxVirtApicSetPendingWrite(pVCpu, XAPIC_OFF_TPR);
                 rcStrict = VINF_SUCCESS;
                 break;
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75619)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImplVmxInstr.cpp.h	(revision 75620)
@@ -911,12 +911,10 @@
 
 /**
- * Signal that a virtual-APIC post instruction-execution action needs to be
- * performed at a later time (post instruction execution).
+ * Sets virtual-APIC write emulation as pending.
  *
  * @param   pVCpu       The cross context virtual CPU structure.
- * @param   offApic     The virtual-APIC page offset that was updated pertaining to
- *                      the event.
- */
-DECLINLINE(void) iemVmxVirtApicSetPostAction(PVMCPU pVCpu, uint16_t offApic)
+ * @param   offApic     The offset in the virtual-APIC page that was written.
+ */
+DECLINLINE(void) iemVmxVirtApicSetPendingWrite(PVMCPU pVCpu, uint16_t offApic)
 {
     Assert(offApic < XAPIC_OFF_END + 4);
@@ -930,26 +928,24 @@
 
     /*
-     * Signal that we need to perform a virtual-APIC action (TPR/PPR/EOI/Self-IPI
+     * Signal that we need to perform virtual-APIC write emulation (TPR/PPR/EOI/Self-IPI
      * virtualization or APIC-write emulation).
      */
-    if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC))
-        VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC);
-}
-
-
-/**
- * Clears any virtual-APIC post instruction-execution action.
- *
- * @returns The virtual-APIC write offset before clearing it.
+    if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
+        VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE);
+}
+
+
+/**
+ * Clears any pending virtual-APIC write emulation.
+ *
+ * @returns The virtual-APIC offset that was written before clearing it.
  * @param   pVCpu       The cross context virtual CPU structure.
- * @param   offApic     The virtual-APIC page offset that was updated pertaining to
- *                      the event.
- */
-DECLINLINE(uint16_t) iemVmxVirtApicClearPostAction(PVMCPU pVCpu)
+ */
+DECLINLINE(uint16_t) iemVmxVirtApicClearPendingWrite(PVMCPU pVCpu)
 {
     uint8_t const offVirtApicWrite = pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite;
     pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = 0;
-    Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC));
-    VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC);
+    Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE));
+    VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_VMX_APIC_WRITE);
     return offVirtApicWrite;
 }
@@ -4164,5 +4160,5 @@
      * virtualized a virtual-APIC write, we must cause a VM-exit.
      */
-    if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_UPDATE_VAPIC))
+    if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
         return true;
 
@@ -4330,8 +4326,11 @@
  *
  * @param   pVCpu       The cross context virtual CPU structure.
- */
-IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicWrite(PVMCPU pVCpu)
-{
-    iemVmxVmcsSetExitQual(pVCpu, pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite);
+ * @param   offApic     The write to the virtual-APIC page offset that caused this
+ *                      VM-exit.
+ */
+IEM_STATIC VBOXSTRICTRC iemVmxVmexitApicWrite(PVMCPU pVCpu, uint16_t offApic)
+{
+    Assert(offApic < XAPIC_OFF_END + 4);
+    iemVmxVmcsSetExitQual(pVCpu, offApic);
     return iemVmxVmexit(pVCpu, VMX_EXIT_APIC_WRITE);
 }
@@ -4444,5 +4443,5 @@
          * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
          */
-        iemVmxVirtApicSetPostAction(pVCpu, offAccess);
+        iemVmxVirtApicSetPendingWrite(pVCpu, offAccess);
     }
     else
@@ -4575,5 +4574,5 @@
          * as for supplying the exit qualification when causing an APIC-write VM-exit.
          */
-        iemVmxVirtApicSetPostAction(pVCpu, offReg);
+        iemVmxVirtApicSetPendingWrite(pVCpu, offReg);
 
         return VINF_VMX_MODIFIES_BEHAVIOR;
@@ -4663,14 +4662,14 @@
      * See Intel spec. 29.1.3 "PPR Virtualization".
      */
-    uint32_t const uVTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
+    uint32_t const uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
     uint32_t const uSvi  = RT_HI_U8(pVmcs->u16GuestIntStatus);
 
     uint32_t uVPpr;
-    if (((uVTpr >> 4) & 0xf) >= ((uSvi >> 4) & 0xf))
-        uVPpr = uVTpr & 0xff;
+    if (((uTpr >> 4) & 0xf) >= ((uSvi >> 4) & 0xf))
+        uVPpr = uTpr & 0xff;
     else
         uVPpr = uSvi & 0xf0;
     iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_PPR, uVPpr);
-    Log2(("ppr_virt: uVTpr=%u uSvi=%u -> VM-exit\n", uVTpr, uSvi));
+    Log2(("ppr_virt: uTpr=%u uSvi=%u -> VM-exit\n", uTpr, uSvi));
 }
 
@@ -4697,5 +4696,5 @@
     {
         uint32_t const uTprThreshold = pVmcs->u32TprThreshold;
-        uint32_t const uVTpr         = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
+        uint32_t const uTpr          = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
 
         /*
@@ -4703,7 +4702,7 @@
          * See Intel spec. 29.1.2 "TPR Virtualization".
          */
-        if (((uVTpr >> 4) & 0xf) < uTprThreshold)
-        {
-            Log2(("tpr_virt: uVTpr=%u uTprThreshold=%u -> VM-exit\n", uVTpr, uTprThreshold));
+        if (((uTpr >> 4) & 0xf) < uTprThreshold)
+        {
+            Log2(("tpr_virt: uTpr=%u uTprThreshold=%u -> VM-exit\n", uTpr, uTprThreshold));
             iemVmxVmcsSetExitQual(pVCpu, 0);
             return iemVmxVmexit(pVCpu, VMX_EXIT_TPR_BELOW_THRESHOLD);
@@ -4824,8 +4823,73 @@
     Assert(pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_APIC_REG_VIRT);
 
-    /** @todo NSTVMX: APIC-write emulation. */
-    RT_NOREF(pVCpu);
-
-    return VERR_IEM_ASPECT_NOT_IMPLEMENTED;
+    /*
+     * Perform APIC-write emulation based on the virtual-APIC register written.
+     * See Intel spec. 29.4.3.2 "APIC-Write Emulation".
+     */
+    uint16_t const offApicWrite = iemVmxVirtApicClearPendingWrite(pVCpu);
+    VBOXSTRICTRC rcStrict;
+    switch (offApicWrite)
+    {
+        case XAPIC_OFF_TPR:
+        {
+            /* Clear bytes 3:1 of the VTPR and perform TPR virtualization. */
+            uint32_t uTpr = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
+            uTpr         &= UINT32_C(0x000000ff);
+            iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_TPR, uTpr);
+            rcStrict = iemVmxTprVirtualization(pVCpu);
+            break;
+        }
+
+        case XAPIC_OFF_EOI:
+        {
+            if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
+            {
+                /* Clear VEOI and perform EOI virtualization. */
+                iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_EOI, 0);
+                rcStrict = iemVmxEoiVirtualization(pVCpu);
+            }
+            else
+                rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
+            break;
+        }
+
+        case XAPIC_OFF_ICR_LO:
+        {
+            if (pVmcs->u32ProcCtls2 & VMX_PROC_CTLS2_VIRT_INT_DELIVERY)
+            {
+                /* If the ICR_LO is valid, write it and perform self-IPI virtualization. */
+                uint32_t const uIcrLo    = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_TPR);
+                uint32_t const fIcrLoMb0 = UINT32_C(0xfffbb700);
+                uint32_t const fIcrLoMb1 = UINT32_C(0x000000f0);
+                if (   !(uIcrLo & fIcrLoMb0)
+                    &&  (uIcrLo & fIcrLoMb1))
+                    rcStrict = iemVmxSelfIpiVirtualization(pVCpu);
+                else
+                    rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
+            }
+            else
+                rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
+            break;
+        }
+
+        case XAPIC_OFF_ICR_HI:
+        {
+            /* Clear bytes 2:0 of VICR_HI. No other virtualization or VM-exit must occur. */
+            uint32_t uIcrHi = iemVmxVirtApicReadRaw32(pVCpu, XAPIC_OFF_ICR_HI);
+            uIcrHi          &= UINT32_C(0xff000000);
+            iemVmxVirtApicWriteRaw32(pVCpu, XAPIC_OFF_ICR_HI, uIcrHi);
+            rcStrict = VINF_SUCCESS;
+            break;
+        }
+
+        default:
+        {
+            /* Writes to any other virtual-APIC register causes an APIC-write VM-exit. */
+            rcStrict = iemVmxVmexitApicWrite(pVCpu, offApicWrite);
+            break;
+        }
+    }
+
+    return rcStrict;
 }
 
