Index: trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 72189)
+++ trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 72190)
@@ -176,4 +176,5 @@
     /*
      * Get the hypercall operation code and modes.
+     * Fast hypercalls have only two or fewer inputs but no output parameters.
      */
     const bool       fIs64BitMode     = CPUMIsGuestIn64BitCodeEx(pCtx);
@@ -181,7 +182,10 @@
     const uint16_t   uHyperOp         = GIM_HV_HYPERCALL_IN_CALL_CODE(uHyperIn);
     const bool       fHyperFast       = GIM_HV_HYPERCALL_IN_IS_FAST(uHyperIn);
-    /*const uint16_t   cHyperReps       = GIM_HV_HYPERCALL_IN_REP_COUNT(uHyperIn); - unused */
-    /*const uint16_t   idxHyperRepStart = GIM_HV_HYPERCALL_IN_REP_START_IDX(uHyperIn); - unused */
+    const uint16_t   cHyperReps       = GIM_HV_HYPERCALL_IN_REP_COUNT(uHyperIn);
+    const uint16_t   idxHyperRepStart = GIM_HV_HYPERCALL_IN_REP_START_IDX(uHyperIn);
     uint64_t         cHyperRepsDone   = 0;
+
+    /* Currently no repeating hypercalls are supported. */
+    RT_NOREF2(cHyperReps, idxHyperRepStart);
 
     int rc     = VINF_SUCCESS;
@@ -332,4 +336,42 @@
             }
 
+            case GIM_HV_EXT_HYPERCALL_OP_QUERY_CAP:              /* Non-rep, extended hypercall. */
+            {
+                if (pHv->uPartFlags & GIM_HV_PART_FLAGS_EXTENDED_HYPERCALLS)
+                {
+                    rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_OUT, &rcHv);
+                    if (   RT_SUCCESS(rc)
+                        && rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        rc = gimR3HvHypercallExtQueryCap(pVM, &rcHv);
+                    }
+                }
+                else
+                {
+                    LogRel(("GIM: HyperV: Denied HvExtCallQueryCapabilities when the feature is not exposed\n"));
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                }
+                break;
+            }
+
+            case GIM_HV_EXT_HYPERCALL_OP_GET_BOOT_ZEROED_MEM:    /* Non-rep, extended hypercall. */
+            {
+                if (pHv->uPartFlags & GIM_HV_PART_FLAGS_EXTENDED_HYPERCALLS)
+                {
+                    rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_OUT, &rcHv);
+                    if (   RT_SUCCESS(rc)
+                        && rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        rc = gimR3HvHypercallExtGetBootZeroedMem(pVM, &rcHv);
+                    }
+                }
+                else
+                {
+                    LogRel(("GIM: HyperV: Denied HvExtCallGetBootZeroedMemory when the feature is not exposed\n"));
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                }
+                break;
+            }
+
             default:
             {
Index: trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 72189)
+++ trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 72190)
@@ -283,4 +283,7 @@
                          ;
 
+        /* Partition features. */
+        pHv->uPartFlags |= GIM_HV_PART_FLAGS_EXTENDED_HYPERCALLS;
+
         /* Expose more if we're posing as Microsoft. We can, if needed, force MSR-based Hv
            debugging by not exposing these bits while exposing the VS interface. The better
@@ -289,5 +292,5 @@
         {
             pHv->uMiscFeat  |= GIM_HV_MISC_FEAT_GUEST_DEBUGGING
-                             | GIM_HV_MISC_FEAT_DEBUG_MSRS;
+                            |  GIM_HV_MISC_FEAT_DEBUG_MSRS;
 
             pHv->uPartFlags |= GIM_HV_PART_FLAGS_DEBUGGING;
@@ -2163,2 +2166,117 @@
 }
 
+
+/**
+ * Performs the HvExtCallQueryCapabilities extended hypercall.
+ *
+ * @returns VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   prcHv       Where to store the result of the hypercall operation.
+ *
+ * @thread  EMT.
+ */
+VMMR3_INT_DECL(int) gimR3HvHypercallExtQueryCap(PVM pVM, int *prcHv)
+{
+    AssertPtr(pVM);
+    AssertPtr(prcHv);
+    PGIMHV pHv  = &pVM->gim.s.u.Hv;
+
+    /*
+     * Grab the parameters.
+     */
+   PGIMHVEXTQUERYCAP pOut = (PGIMHVEXTQUERYCAP)pHv->pbHypercallOut;
+
+    /*
+     * Perform the hypercall.
+     */
+    pOut->fCapabilities = GIM_HV_EXT_HYPERCALL_CAP_ZERO_MEM;
+
+    /*
+     * Update the guest memory with result.
+     */
+    int rcHv;
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTQUERYCAP));
+    if (RT_SUCCESS(rc))
+    {
+        rcHv = GIM_HV_STATUS_SUCCESS;
+        LogRel(("GIM: HyperV: Queried extended hypercall capabilities %#RX64 at %#RGp\n", pOut->fCapabilities,
+                pHv->GCPhysHypercallOut));
+    }
+    else
+    {
+        rcHv = GIM_HV_STATUS_OPERATION_DENIED;
+        LogRelMax(10, ("GIM: HyperV: HvHypercallExtQueryCap failed to update guest memory. rc=%Rrc\n", rc));
+        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
+    }
+
+    *prcHv = rcHv;
+    return rc;
+}
+
+
+/**
+ * Performs the HvExtCallGetBootZeroedMemory extended hypercall.
+ *
+ * @returns VBox status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   prcHv       Where to store the result of the hypercall operation.
+ *
+ * @thread  EMT.
+ */
+VMMR3_INT_DECL(int) gimR3HvHypercallExtGetBootZeroedMem(PVM pVM, int *prcHv)
+{
+    AssertPtr(pVM);
+    AssertPtr(prcHv);
+    PGIMHV pHv  = &pVM->gim.s.u.Hv;
+
+    /*
+     * Grab the parameters.
+     */
+    PGIMHVEXTGETBOOTZEROMEM pOut = (PGIMHVEXTGETBOOTZEROMEM)pHv->pbHypercallOut;
+
+    /*
+     * Perform the hypercall.
+     */
+    uint32_t const cRanges = PGMR3PhysGetRamRangeCount(pVM);
+    pOut->cPages = 0;
+    for (uint32_t iRange = 0; iRange < cRanges; iRange++)
+    {
+        RTGCPHYS GCPhysStart;
+        RTGCPHYS GCPhysEnd;
+        int rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, NULL /* fIsMmio */);
+        if (RT_FAILURE(rc))
+        {
+            LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem: PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n",
+                           iRange, rc));
+            *prcHv = GIM_HV_STATUS_OPERATION_DENIED;
+            return rc;
+        }
+
+        RTGCPHYS const cbRange = RT_ALIGN(GCPhysEnd - GCPhysStart + 1, PAGE_SIZE);
+        pOut->cPages += cbRange >> GIM_HV_PAGE_SHIFT;
+        if (iRange == 0)
+            pOut->GCPhysStart = GCPhysStart;
+    }
+
+    /*
+     * Update the guest memory with result.
+     */
+    int rcHv;
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVEXTGETBOOTZEROMEM));
+    if (RT_SUCCESS(rc))
+    {
+        LogRel(("GIM: HyperV: Queried boot zeroed guest memory range (starting at %#RGp spanning %u pages) at %#RGp\n",
+                pOut->GCPhysStart, pOut->cPages, pHv->GCPhysHypercallOut));
+        rcHv = GIM_HV_STATUS_SUCCESS;
+    }
+    else
+    {
+        rcHv = GIM_HV_STATUS_OPERATION_DENIED;
+        LogRelMax(10, ("GIM: HyperV: HvHypercallExtGetBootZeroedMem failed to update guest memory. rc=%Rrc\n", rc));
+        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
+    }
+
+    *prcHv = rcHv;
+    return rc;
+}
+
Index: trunk/src/VBox/VMM/include/GIMHvInternal.h
===================================================================
--- trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 72189)
+++ trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 72190)
@@ -586,4 +586,23 @@
 /** Reset debug session. */
 #define GIM_HV_HYPERCALL_OP_RESET_DEBUG_SESSION   0x6B
+/** @} */
+
+/** @name Hyper-V extended hypercall op codes.
+ * @{
+ */
+/** Query extended hypercall capabilities. */
+#define GIM_HV_EXT_HYPERCALL_OP_QUERY_CAP                0x8001
+/** Query guest physical address range that has zero'd filled memory. */
+#define GIM_HV_EXT_HYPERCALL_OP_GET_BOOT_ZEROED_MEM      0x8002
+/** @} */
+
+
+/** @name Hyper-V Extended hypercall - HvExtCallQueryCapabilities.
+ * @{
+ */
+/** Boot time zeroed pages. */
+#define GIM_HV_EXT_HYPERCALL_CAP_ZERO_MEM                       RT_BIT_64(0)
+/** Whether boot time zeroed pages capability is enabled. */
+#define GIM_HV_EXT_HYPERCALL_CAP_IS_ZERO_MEM_ENABLED(a)         RT_BOOL((a) & GIM_HV_EXT_HYPERCALL_CAP_ZERO_MEM)
 /** @} */
 
@@ -1036,4 +1055,27 @@
 typedef GIMHVDEBUGRETRIEVEOUT *PGIMHVDEBUGRETRIEVEOUT;
 AssertCompileSize(GIMHVDEBUGRETRIEVEOUT, 8);
+
+/**
+ * HvExtCallQueryCapabilities hypercall output.
+ */
+typedef struct GIMHVEXTQUERYCAP
+{
+    uint64_t fCapabilities;
+} GIMHVEXTQUERYCAP;
+/** Pointer to a HvExtCallQueryCapabilities output struct. */
+typedef GIMHVEXTQUERYCAP *PGIMHVEXTQUERYCAP;
+AssertCompileSize(GIMHVEXTQUERYCAP, 8);
+
+/**
+ * HvExtCallGetBootZeroedMemory hypercall output.
+ */
+typedef struct GIMHVEXTGETBOOTZEROMEM
+{
+    RTGCPHYS GCPhysStart;
+    uint64_t cPages;
+} GIMHVEXTGETBOOTZEROMEM;
+/** Pointer to a HvExtCallGetBootZeroedMemory output struct. */
+typedef GIMHVEXTGETBOOTZEROMEM *PGIMHVEXTGETBOOTZEROMEM;
+AssertCompileSize(GIMHVEXTGETBOOTZEROMEM, 16);
 /** @} */
 
@@ -1041,4 +1083,6 @@
 /** Hyper-V page size.  */
 #define GIM_HV_PAGE_SIZE                          4096
+/** Hyper-V page shift. */
+#define GIM_HV_PAGE_SHIFT                         12
 
 /** Microsoft Hyper-V vendor signature. */
@@ -1313,4 +1357,7 @@
 VMMR3_INT_DECL(int)             gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead,
                                                  uint32_t cMsTimeout, bool fUdpPkt);
+VMMR3_INT_DECL(int)             gimR3HvHypercallExtQueryCap(PVM pVM, int *prcHv);
+VMMR3_INT_DECL(int)             gimR3HvHypercallExtGetBootZeroedMem(PVM pVM, int *prcHv);
+
 #endif /* IN_RING3 */
 
