Index: trunk/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp	(revision 58267)
+++ trunk/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp	(revision 58268)
@@ -77,4 +77,33 @@
     PMDL                apMdls[1];
 } RTR0MEMOBJNT, *PRTR0MEMOBJNT;
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+/** Pointer to the MmProtectMdlSystemAddress kernel function if it's available.
+ * This API was introduced in XP. */
+static decltype(MmProtectMdlSystemAddress) *g_pfnMmProtectMdlSystemAddress = NULL;
+/** Set if we've resolved the dynamic APIs. */
+static bool volatile g_fResolvedDynamicApis = false;
+static ULONG g_uMajorVersion = 5;
+static ULONG g_uMinorVersion = 1;
+
+
+static void rtR0MemObjNtResolveDynamicApis(void)
+{
+    ULONG uBuildNumber  = 0;
+    PsGetVersion(&g_uMajorVersion, &g_uMinorVersion, &uBuildNumber, NULL);
+
+#ifndef IPRT_TARGET_NT4 /* MmGetSystemRoutineAddress was introduced in w2k. */
+
+    UNICODE_STRING RoutineName;
+    RtlInitUnicodeString(&RoutineName, L"MmProtectMdlSystemAddress");
+    g_pfnMmProtectMdlSystemAddress = (decltype(MmProtectMdlSystemAddress) *)MmGetSystemRoutineAddress(&RoutineName);
+
+#endif
+    ASMCompilerBarrier();
+    g_fResolvedDynamicApis = true;
+}
 
 
@@ -820,8 +849,124 @@
 DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
 {
-    NOREF(pMem);
-    NOREF(offSub);
-    NOREF(cbSub);
-    NOREF(fProt);
+    PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
+    if (!g_fResolvedDynamicApis)
+        rtR0MemObjNtResolveDynamicApis();
+
+    /*
+     * Seems there are some issues with this MmProtectMdlSystemAddress API, so
+     * this code isn't currently enabled until we've tested it with the verifier.
+     */
+#if 0
+    /*
+     * The API we've got requires a kernel mapping.
+     */
+    if (   pMemNt->cMdls
+        && g_pfnMmProtectMdlSystemAddress
+        && (g_uMajorVersion > 6 || (g_uMajorVersion == 6 && g_uMinorVersion >= 1)) /* Windows 7 and later. */
+        && pMemNt->Core.pv != NULL
+        && (   pMemNt->Core.enmType == RTR0MEMOBJTYPE_PAGE
+            || pMemNt->Core.enmType == RTR0MEMOBJTYPE_LOW
+            || pMemNt->Core.enmType == RTR0MEMOBJTYPE_CONT
+            || (   pMemNt->Core.enmType             == RTR0MEMOBJTYPE_LOCK
+                && pMemNt->Core.u.Lock.R0Process    == NIL_RTPROCESS)
+            || (   pMemNt->Core.enmType             == RTR0MEMOBJTYPE_MAPPING
+                && pMemNt->Core.u.Mapping.R0Process == NIL_RTPROCESS) ) )
+    {
+        /* Convert the protection. */
+        LOCK_OPERATION enmLockOp;
+        ULONG fAccess;
+        switch (fProt)
+        {
+            case RTMEM_PROT_NONE:
+                fAccess = PAGE_NOACCESS;
+                enmLockOp = IoReadAccess;
+                break;
+            case RTMEM_PROT_READ:
+                fAccess = PAGE_READONLY;
+                enmLockOp = IoReadAccess;
+                break;
+            case RTMEM_PROT_WRITE:
+            case RTMEM_PROT_WRITE | RTMEM_PROT_READ:
+                fAccess = PAGE_READWRITE;
+                enmLockOp = IoModifyAccess;
+                break;
+            case RTMEM_PROT_EXEC:
+                fAccess = PAGE_EXECUTE;
+                enmLockOp = IoReadAccess;
+                break;
+            case RTMEM_PROT_EXEC | RTMEM_PROT_READ:
+                fAccess = PAGE_EXECUTE_READ;
+                enmLockOp = IoReadAccess;
+                break;
+            case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE:
+            case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ:
+                fAccess = PAGE_EXECUTE_READWRITE;
+                enmLockOp = IoModifyAccess;
+                break;
+            default:
+                AssertFailedReturn(VERR_INVALID_FLAGS);
+        }
+
+        NTSTATUS rcNt = STATUS_SUCCESS;
+# if 0 /** @todo test this against the verifier. */
+        if (offSub == 0 && pMemNt->Core.cb == cbSub)
+        {
+            uint32_t iMdl = pMemNt->cMdls;
+            while (iMdl-- > 0)
+            {
+                rcNt = g_pfnMmProtectMdlSystemAddress(pMemNt->apMdls[i], fAccess);
+                if (!NT_SUCCESS(rcNt))
+                    break;
+            }
+        }
+        else
+# endif
+        {
+            /*
+             * We ASSUME the following here:
+             *   - MmProtectMdlSystemAddress can deal with nonpaged pool memory
+             *   - MmProtectMdlSystemAddress doesn't actually store anything in the MDL we pass it.
+             *   - We are not required to call MmProtectMdlSystemAddress with PAGE_READWRITE for the
+             *     exact same ranges prior to freeing them.
+             *
+             * So, we lock the pages temporarily, call the API and unlock them.
+             */
+            uint8_t *pbCur = (uint8_t *)pMemNt->Core.pv + offSub;
+            while (cbSub > 0 && NT_SUCCESS(rcNt))
+            {
+                size_t cbCur = cbSub;
+                if (cbCur > MAX_LOCK_MEM_SIZE)
+                    cbCur = MAX_LOCK_MEM_SIZE;
+                PMDL pMdl = IoAllocateMdl(pbCur, (ULONG)cbCur, FALSE, FALSE, NULL);
+                if (pMdl)
+                {
+                    __try
+                    {
+                        MmProbeAndLockPages(pMdl, KernelMode, enmLockOp);
+                    }
+                    __except(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        rcNt = GetExceptionCode();
+                    }
+                    if (NT_SUCCESS(rcNt))
+                    {
+                        rcNt = g_pfnMmProtectMdlSystemAddress(pMdl, fAccess);
+                        MmUnlockPages(pMdl);
+                    }
+                    IoFreeMdl(pMdl);
+                }
+                else
+                    rcNt = STATUS_NO_MEMORY;
+                pbCur += cbCur;
+                cbSub -= cbCur;
+            }
+        }
+
+        if (NT_SUCCESS(rcNt))
+            return VINF_SUCCESS;
+        return RTErrConvertFromNtStatus(rcNt);
+    }
+#endif
+
     return VERR_NOT_SUPPORTED;
 }
