Index: trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp	(revision 70335)
+++ trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp	(revision 70336)
@@ -110,9 +110,7 @@
 /** RtlGetVersion, introduced in ??. */
 PFNRTRTLGETVERSION                      g_pfnrtRtlGetVersion;
-#ifndef RT_ARCH_AMD64
+#ifdef RT_ARCH_X86
 /** KeQueryInterruptTime - exported/new in Windows 2000. */
 PFNRTKEQUERYINTERRUPTTIME               g_pfnrtKeQueryInterruptTime;
-/** KeQuerySystemTime - exported/new in Windows 2000. */
-PFNRTKEQUERYSYSTEMTIME                  g_pfnrtKeQuerySystemTime;
 #endif
 /** KeQueryInterruptTimePrecise - new in Windows 8. */
@@ -129,5 +127,5 @@
 
 /** The combined NT version, see RTNT_MAKE_VERSION. */
-uint32_t                                g_uRtNtVersion;
+uint32_t                                g_uRtNtVersion = RTNT_MAKE_VERSION(4, 0);
 /** The major version number. */
 uint8_t                                 g_uRtNtMajorVer;
@@ -314,7 +312,6 @@
 
     GET_SYSTEM_ROUTINE_TYPE(RtlGetVersion, PFNRTRTLGETVERSION);
-#ifndef RT_ARCH_AMD64
+#ifdef RT_ARCH_X86
     GET_SYSTEM_ROUTINE(KeQueryInterruptTime);
-    GET_SYSTEM_ROUTINE(KeQuerySystemTime);
 #endif
     GET_SYSTEM_ROUTINE_TYPE(KeQueryInterruptTimePrecise, PFNRTKEQUERYINTERRUPTTIMEPRECISE);
@@ -327,5 +324,12 @@
     g_puRtMmSystemRangeStart   = (uintptr_t const *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "MmSystemRangeStart");
 
+#ifdef RT_ARCH_X86
+    rc = rtR0Nt3InitSymbols(hKrnlInfo);
     RTR0DbgKrnlInfoRelease(hKrnlInfo);
+    if (RT_FAILURE(rc))
+        return rc;
+#else
+    RTR0DbgKrnlInfoRelease(hKrnlInfo);
+#endif
 
     /*
Index: trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h	(revision 70335)
+++ trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h	(revision 70336)
@@ -93,7 +93,6 @@
 
 extern PFNRTRTLGETVERSION                      g_pfnrtRtlGetVersion;
-#ifndef RT_ARCH_AMD64
+#ifdef RT_ARCH_X86
 extern PFNRTKEQUERYINTERRUPTTIME               g_pfnrtKeQueryInterruptTime;
-extern PFNRTKEQUERYSYSTEMTIME                  g_pfnrtKeQuerySystemTime;
 #endif
 extern PFNRTKEQUERYINTERRUPTTIMEPRECISE        g_pfnrtKeQueryInterruptTimePrecise;
@@ -125,5 +124,8 @@
 DECLHIDDEN(int)  rtR0MpNtInit(struct RTNTSDBOSVER const *pOsVerInfo);
 DECLHIDDEN(void) rtR0MpNtTerm(void);
-DECLHIDDEN(int) rtMpNtSetTargetProcessorDpc(KDPC *pDpc, RTCPUID idCpu);
+DECLHIDDEN(int)  rtMpNtSetTargetProcessorDpc(KDPC *pDpc, RTCPUID idCpu);
+#if defined(RT_ARCH_X86) && defined(NIL_RTDBGKRNLINFO)
+DECLHIDDEN(int)  rtR0Nt3InitSymbols(RTDBGKRNLINFO hKrnlInfo);
+#endif
 
 RT_C_DECLS_END
Index: trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-r0drv-nt.cpp	(revision 70335)
+++ trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-r0drv-nt.cpp	(revision 70336)
@@ -29,12 +29,4 @@
 *   Header Files                                                                                                                 *
 *********************************************************************************************************************************/
-#define PsGetVersion                PsGetVersion_Nt4Plus
-#define ZwQuerySystemInformation    ZwQuerySystemInformation_Nt4Plus
-#define KeInitializeTimerEx         KeInitializeTimerEx_Nt4Plus
-#define KeSetTimerEx                KeSetTimerEx_Nt4Plus
-#define IoAttachDeviceToDeviceStack IoAttachDeviceToDeviceStack_Nt4Plus
-#define PsGetCurrentProcessId       PsGetCurrentProcessId_Nt4Plus
-#define ZwYieldExecution            ZwYieldExecution_Nt4Plus
-
 #define _IMAGE_NT_HEADERS           RT_CONCAT(_IMAGE_NT_HEADERS,ARCH_BITS)
 #include "the-nt-kernel.h"
@@ -42,19 +34,20 @@
 
 #include <iprt/assert.h>
+#include <iprt/asm.h>
 #include <iprt/ctype.h>
+#include <iprt/dbg.h>
 #include <iprt/err.h>
 #include <iprt/log.h>
 #include <iprt/string.h>
+#include <iprt/x86.h>
 #include <iprt/formats/mz.h>
 #include <iprt/formats/pecoff.h>
 #include "internal-r0drv-nt.h"
 
-#undef PsGetVersion
-#undef ZwQuerySystemInformation
-#undef KeInitializeTimerEx
-#undef KeSetTimerEx
-#undef IoAttachDeviceToDeviceStack
-#undef PsGetCurrentProcessId
-#undef ZwYieldExecution
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+DECLASM(void) rtNt3InitSymbolsAssembly(void); /* in nt3fakesA-r0drv-nt.asm */
 
 
@@ -74,4 +67,52 @@
 static uint32_t         g_cbNt3Hal      = _512K;
 static bool volatile    g_fNt3ModuleInfoInitialized = false;
+
+
+RT_C_DECLS_BEGIN
+/** @name KPIs we provide fallback implementations for.
+ *
+ * The assembly init routine will point the __imp_xxx variable to the NT
+ * implementation if available, using the fallback if not.
+ * @{  */
+decltype(PsGetVersion)                     *g_pfnrtPsGetVersion;
+decltype(ZwQuerySystemInformation)         *g_pfnrtZwQuerySystemInformation;
+decltype(KeSetTimerEx)                     *g_pfnrtKeSetTimerEx;
+decltype(IoAttachDeviceToDeviceStack)      *g_pfnrtIoAttachDeviceToDeviceStack;
+decltype(PsGetCurrentProcessId)            *g_pfnrtPsGetCurrentProcessId;
+decltype(ZwYieldExecution)                 *g_pfnrtZwYieldExecution;
+decltype(ExAcquireFastMutex)               *g_pfnrtExAcquireFastMutex;
+decltype(ExReleaseFastMutex)               *g_pfnrtExReleaseFastMutex;
+/** @} */
+
+/** @name Fastcall optimizations not present in NT 3.1.
+ *
+ * We try resolve both the stdcall and fastcall variants and patch it up in
+ * assembly. The last four routines are in the hal.
+ *
+ * @{  */
+decltype(IofCompleteRequest)               *g_pfnrtIofCompleteRequest;
+decltype(ObfDereferenceObject)             *g_pfnrtObfDereferenceObject;
+decltype(IofCallDriver)                    *g_pfnrtIofCallDriver;
+decltype(KfAcquireSpinLock)                *g_pfnrtKfAcquireSpinLock;
+decltype(KfReleaseSpinLock)                *g_pfnrtKfReleaseSpinLock;
+decltype(KfLowerIrql)                      *g_pfnrtKfLowerIrql;
+decltype(KfRaiseIrql)                      *g_pfnrtKfRaiseIrql;
+
+VOID                            (__stdcall *g_pfnrtIoCompleteRequest)(PIRP, CCHAR);
+LONG_PTR                        (__stdcall *g_pfnrtObDereferenceObject)(PVOID);
+NTSTATUS                        (__stdcall *g_pfnrtIoCallDriver)(PDEVICE_OBJECT, PIRP);
+KIRQL                           (__stdcall *g_pfnrtKeAcquireSpinLock)(PKSPIN_LOCK);
+VOID                            (__stdcall *g_pfnrtKeReleaseSpinLock)(PKSPIN_LOCK, KIRQL);
+VOID                            (__stdcall *g_pfnrtKeLowerIrql)(KIRQL);
+KIRQL                           (__stdcall *g_pfnrtKeRaiseIrql)(KIRQL);
+/** @} */
+
+/** @name DATA exports and associated stuff
+ * @{ */
+/** Import address table entry for KeTickCount (defined in asm). */
+extern KSYSTEM_TIME                        *_imp__KeTickCount;
+/** @} */
+
+RT_C_DECLS_END
 
 
@@ -237,4 +278,6 @@
 /**
  * Figure out the NT 3 version from the registry.
+ *
+ * @note this will be called before the rtR0Nt3InitSymbols is called.
  */
 static void rtR0Nt3InitVersion(void)
@@ -275,5 +318,5 @@
 
 extern "C" DECLEXPORT(BOOLEAN) __stdcall
-PsGetVersion(ULONG *puMajor, ULONG *puMinor, ULONG *puBuildNo, UNICODE_STRING *pCsdStr)
+Nt3Fb_PsGetVersion(ULONG *puMajor, ULONG *puMinor, ULONG *puBuildNo, UNICODE_STRING *pCsdStr)
 {
     if (!g_fNt3VersionInitialized)
@@ -365,5 +408,5 @@
 
 extern "C" DECLEXPORT(NTSTATUS) __stdcall
-ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS enmClass, PVOID pvBuf, ULONG cbBuf, PULONG pcbActual)
+Nt3Fb_ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS enmClass, PVOID pvBuf, ULONG cbBuf, PULONG pcbActual)
 {
     switch (enmClass)
@@ -415,7 +458,150 @@
 }
 
+/**
+ * Calculates the length indicated by an ModR/M sequence.
+ *
+ * @returns Length, including RM byte.
+ * @param   bRm         The RM byte.
+ */
+static uint32_t rtR0Nt3CalcModRmLength(uint8_t bRm)
+{
+    uint32_t cbRm = 1;
+
+    if (   (bRm & X86_MODRM_MOD_MASK) == 3
+        || (bRm & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5)
+        cbRm += 4; /* disp32 */
+    else if ((bRm & X86_MODRM_MOD_MASK) == 1)
+        cbRm += 1; /* disp8 */
+    else if ((bRm & X86_MODRM_MOD_MASK) == 2)
+        cbRm += 2; /* disp16 */
+
+    if ((bRm & X86_MODRM_RM_MASK) == 4 && (bRm & X86_MODRM_MOD_MASK) != 3)
+        cbRm += 1; /* SIB */
+
+    return cbRm;
+}
+
+
+/**
+ * Init symbols.
+ *
+ * This is called after both ZwQuerySystemInformation and PsGetVersion are used
+ * for the first time.
+ *
+ * @returns IPRT status code
+ * @param   hKrnlInfo           Kernel symbol digger handle.
+ */
+DECLHIDDEN(int) rtR0Nt3InitSymbols(RTDBGKRNLINFO hKrnlInfo)
+{
+    /*
+     * Resolve symbols.  (We set C variables (g_pfnrtXxx) here, not the __imp__Xxx ones.)
+     */
+#define GET_SYSTEM_ROUTINE(a_fnName) do { \
+            RT_CONCAT(g_pfnrt, a_fnName) = (decltype(RT_CONCAT(g_pfnrt, a_fnName)))RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, #a_fnName); \
+        } while (0)
+
+    GET_SYSTEM_ROUTINE(PsGetVersion);
+    GET_SYSTEM_ROUTINE(ZwQuerySystemInformation);
+    GET_SYSTEM_ROUTINE(KeSetTimerEx);
+    GET_SYSTEM_ROUTINE(IoAttachDeviceToDeviceStack);
+    GET_SYSTEM_ROUTINE(PsGetCurrentProcessId);
+    GET_SYSTEM_ROUTINE(ZwYieldExecution);
+    GET_SYSTEM_ROUTINE(ExAcquireFastMutex);
+    GET_SYSTEM_ROUTINE(ExReleaseFastMutex);
+
+#define GET_FAST_CALL_SYSTEM_ROUTINE(a_fnFastcall, a_fnStdcall) do { \
+            GET_SYSTEM_ROUTINE(a_fnFastcall); \
+            GET_SYSTEM_ROUTINE(a_fnStdcall); \
+            AssertLogRelReturn(RT_CONCAT(g_pfnrt,a_fnFastcall) || RT_CONCAT(g_pfnrt,a_fnStdcall), VERR_INTERNAL_ERROR_3); \
+        } while (0)
+    GET_FAST_CALL_SYSTEM_ROUTINE(IofCompleteRequest,   IoCompleteRequest);
+    GET_FAST_CALL_SYSTEM_ROUTINE(ObfDereferenceObject, ObDereferenceObject);
+    GET_FAST_CALL_SYSTEM_ROUTINE(IofCallDriver,        IofCallDriver);
+    GET_FAST_CALL_SYSTEM_ROUTINE(KfAcquireSpinLock,    KeAcquireSpinLock);
+    GET_FAST_CALL_SYSTEM_ROUTINE(KfReleaseSpinLock,    KeReleaseSpinLock);
+    GET_FAST_CALL_SYSTEM_ROUTINE(KfLowerIrql,          KeLowerIrql);
+    GET_FAST_CALL_SYSTEM_ROUTINE(KfRaiseIrql,          KeRaiseIrql);
+
+    /*
+     * We need to call assembly to update the __imp__Xxx entries, since C
+     * doesn't allow '@' in symbols.
+     */
+    rtNt3InitSymbolsAssembly();
+
+    /*
+     * Tick count data.  We disassemble KeQueryTickCount until we find the
+     * first absolute address referenced in it.
+     *      %80105b70 8b 44 24 04             mov eax, dword [esp+004h]
+     *      %80105b74 c7 40 04 00 00 00 00    mov dword [eax+004h], 000000000h
+     *      %80105b7b 8b 0d 88 70 19 80       mov ecx, dword [080197088h]
+     *      %80105b81 89 08                   mov dword [eax], ecx
+     *      %80105b83 c2 04 00                retn 00004h
+     */
+    _imp__KeTickCount = (decltype(_imp__KeTickCount))RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeTickCount");
+    if (!_imp__KeTickCount)
+    {
+        Assert(g_uNt3MajorVer == 3 && g_uNt3MinorVer < 50);
+        uint8_t const *pbCode = (uint8_t const *)RTR0DbgKrnlInfoGetSymbol(hKrnlInfo, NULL, "KeQueryTickCount");
+        AssertLogRelReturn(pbCode, VERR_INTERNAL_ERROR_2);
+
+        for (uint32_t off = 0; off < 128 && _imp__KeTickCount == NULL;)
+        {
+            uint8_t const b1 = pbCode[off++];
+            switch (b1)
+            {
+                case 0x89:
+                    /* mov reg, r/m     ; We're looking for absolute address in r/m. */
+                    if ((pbCode[off] & (X86_MODRM_MOD_MASK | X86_MODRM_RM_MASK)) == 5 /*disp32*/)
+                        _imp__KeTickCount = *(KSYSTEM_TIME **)&pbCode[off + 1];
+                    RT_FALL_THRU();
+                case 0x8b:
+                    off += rtR0Nt3CalcModRmLength(pbCode[off]);
+                    break;
+
+                case 0xc7:
+                    if ((pbCode[off] & X86_MODRM_REG_MASK) == 0) /* mov r/m, imm32 */
+                        off += rtR0Nt3CalcModRmLength(pbCode[off]) + 4;
+                    else
+                    {
+                        RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered unknown opcode at %#x! %.*Rhxs\n",
+                                            off - 1, RT_MAX(off + 16, RT_MIN(PAGE_SIZE - ((uintptr_t)pbCode & PAGE_OFFSET_MASK), 128)), pbCode);
+                        return VERR_INTERNAL_ERROR_3;
+                    }
+                    break;
+
+                case 0xc2: /* ret iw */
+                    RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered RET! %.*Rhxs\n",
+                                        off + 2, pbCode);
+                    return VERR_INTERNAL_ERROR_3;
+
+                default:
+                    RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount! Encountered unknown opcode at %#x! %.*Rhxs\n",
+                                        off - 1, RT_MAX(off + 16, RT_MIN(PAGE_SIZE - ((uintptr_t)pbCode & PAGE_OFFSET_MASK), 128)), pbCode);
+                    return VERR_INTERNAL_ERROR_3;
+
+                /* Just in case: */
+
+                case 0xa1: /* mov eax, [m32] */
+                    _imp__KeTickCount = *(KSYSTEM_TIME **)&pbCode[off];
+                    off += 4;
+                    break;
+
+                case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: /* push reg */
+                    break;
+            }
+        }
+        if (!_imp__KeTickCount)
+        {
+            RTLogBackdoorPrintf("rtR0Nt3InitSymbols: Failed to find KeTickCount after 128 bytes! %.*Rhxs\n", 128, pbCode);
+            return VERR_INTERNAL_ERROR_3;
+        }
+    }
+
+    return VINF_SUCCESS;
+}
+
 
 extern "C" DECLEXPORT(VOID)
-KeInitializeTimerEx(PKTIMER pTimer, TIMER_TYPE enmType)
+Nt3Fb_KeInitializeTimerEx(PKTIMER pTimer, TIMER_TYPE enmType)
 {
     KeInitializeTimer(pTimer);
@@ -427,5 +613,5 @@
 
 extern "C" DECLEXPORT(BOOLEAN) __stdcall
-KeSetTimerEx(PKTIMER pTimer, LARGE_INTEGER DueTime, LONG cMsPeriod, PKDPC pDpc)
+Nt3Fb_KeSetTimerEx(PKTIMER pTimer, LARGE_INTEGER DueTime, LONG cMsPeriod, PKDPC pDpc)
 {
     AssertReturn(cMsPeriod == 0, FALSE);
@@ -435,5 +621,5 @@
 
 extern "C" DECLEXPORT(PDEVICE_OBJECT)
-IoAttachDeviceToDeviceStack(PDEVICE_OBJECT pSourceDevice, PDEVICE_OBJECT pTargetDevice)
+Nt3Fb_IoAttachDeviceToDeviceStack(PDEVICE_OBJECT pSourceDevice, PDEVICE_OBJECT pTargetDevice)
 {
     NOREF(pSourceDevice); NOREF(pTargetDevice);
@@ -443,5 +629,5 @@
 
 extern "C" DECLEXPORT(HANDLE)
-PsGetCurrentProcessId(void)
+Nt3Fb_PsGetCurrentProcessId(void)
 {
     if (!g_fNt3VersionInitialized)
@@ -457,5 +643,5 @@
 
 extern "C" DECLEXPORT(NTSTATUS)
-ZwYieldExecution(VOID)
+Nt3Fb_ZwYieldExecution(VOID)
 {
     LARGE_INTEGER Interval;
@@ -465,2 +651,44 @@
 }
 
+
+/**
+ * This is a simple implementation of the fast mutex api introduced in 3.50.
+ */
+extern "C" DECLEXPORT(VOID) FASTCALL
+Nt3Fb_ExAcquireFastMutex(PFAST_MUTEX pFastMtx)
+{
+    PETHREAD pSelf = PsGetCurrentThread();
+    KIRQL    OldIrql;
+    KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+    /* The Count member is initialized to 1.  So if we decrement it to zero, we're
+       the first locker and owns the mutex.  Otherwise we must wait for our turn. */
+    int32_t  cLockers = ASMAtomicDecS32((int32_t volatile *)&pFastMtx->Count);
+    if (cLockers != 0)
+    {
+        ASMAtomicIncU32((uint32_t volatile *)&pFastMtx->Contention);
+        KeWaitForSingleObject(&pFastMtx->Event, Executive, KernelMode, FALSE /*fAlertable*/, NULL /*pTimeout*/);
+    }
+
+    pFastMtx->Owner   = (PKTHREAD)pSelf;
+    pFastMtx->OldIrql = OldIrql;
+}
+
+
+/**
+ * This is a simple implementation of the fast mutex api introduced in 3.50.
+ */
+extern "C" DECLEXPORT(VOID) FASTCALL
+Nt3Fb_ExReleaseFastMutex(PFAST_MUTEX pFastMtx)
+{
+    AssertMsg(pFastMtx->Owner == (PKTHREAD)PsGetCurrentThread(), ("Owner=%p, expected %p\n", pFastMtx->Owner, PsGetCurrentThread()));
+
+    KIRQL    OldIrql  = pFastMtx->OldIrql;
+    pFastMtx->Owner   = NULL;
+    int32_t  cLockers = ASMAtomicIncS32((int32_t volatile *)&pFastMtx->Count);
+    if (cLockers < 0)
+        KeSetEvent(&pFastMtx->Event, EVENT_INCREMENT, FALSE /*fWait*/);
+    if (OldIrql != APC_LEVEL)
+        KeLowerIrql(OldIrql);
+}
+
Index: trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-stub-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-stub-r0drv-nt.cpp	(revision 70336)
+++ trunk/src/VBox/Runtime/r0drv/nt/nt3fakes-stub-r0drv-nt.cpp	(revision 70336)
@@ -0,0 +1,42 @@
+/* $Id$ */
+/** @file
+ * IPRT - NT 3.x fakes for NT 4.0+ KPIs, init stub.
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "the-nt-kernel.h"
+#include <iprt/err.h>
+#include <iprt/dbg.h>
+#include "internal-r0drv-nt.h"
+
+
+int rtR0Nt3InitSymbols(RTDBGKRNLINFO hKrnlInfo)
+{
+    NOREF(hKrnlInfo);
+    return VINF_SUCCESS;
+}
+
Index: trunk/src/VBox/Runtime/r0drv/nt/nt3fakesA-r0drv-nt.asm
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/nt3fakesA-r0drv-nt.asm	(revision 70335)
+++ trunk/src/VBox/Runtime/r0drv/nt/nt3fakesA-r0drv-nt.asm	(revision 70336)
@@ -30,32 +30,106 @@
 %include "iprt/asmdefs.mac"
 
+%undef NAME
+%define NAME(name) NAME_OVERLOAD(name)
+
 BEGINCODE
 
-extern      _PsGetVersion@16
-GLOBALNAME _imp__PsGetVersion@16
-    dd      _PsGetVersion@16
+;;
+; Called from rtR0Nt3InitSymbols after symbols have been resolved.
+BEGINPROC _rtNt3InitSymbolsAssembly
+        push    ebp
+        mov     ebp, esp
 
-extern      _ZwQuerySystemInformation@16
-GLOBALNAME _imp__ZwQuerySystemInformation@16
-    dd      _ZwQuerySystemInformation@16
+;;
+; @param 1  The fastcall name.
+; @param 2  Byte size of arguments.
+%macro DefineImportDataAndInitCode 3
+extern          $%1 %+ Nt3Fb_ %+ %2 %+ @ %+ %3
+BEGINDATA
+extern          _g_pfnrt %+ %2
+GLOBALNAME __imp_ %+ %1 %+ %2 %+ @ %+ %3
+        dd      $%1 %+ Nt3Fb_ %+ %2 %+ @ %+ %3
+BEGINCODE
+        mov     eax, [_g_pfnrt %+ %2]
+        test    eax, eax
+        jz      %%next
+        mov     [__imp_ %+ %1 %+ %2 %+ @ %+ %3], eax
+%%next:
+%endmacro
 
-extern      _KeInitializeTimerEx@8
-GLOBALNAME _imp__KeInitializeTimerEx@8
-    dd      _KeInitializeTimerEx@8
+        DefineImportDataAndInitCode _,PsGetVersion, 16
+        DefineImportDataAndInitCode _,ZwQuerySystemInformation, 16
+        DefineImportDataAndInitCode _,KeSetTimerEx, 20
+        DefineImportDataAndInitCode _,IoAttachDeviceToDeviceStack, 8
+        DefineImportDataAndInitCode _,PsGetCurrentProcessId, 0
+        DefineImportDataAndInitCode _,ZwYieldExecution, 0
+        DefineImportDataAndInitCode @,ExAcquireFastMutex, 4
+        DefineImportDataAndInitCode @,ExReleaseFastMutex, 4
 
-extern      _KeSetTimerEx@20
-GLOBALNAME _imp__KeSetTimerEx@20
-    dd      _KeSetTimerEx@20
+        xor     eax, eax
+        leave
+        ret
+ENDPROC _rtNt3InitSymbolsAssembly
 
-extern      _IoAttachDeviceToDeviceStack@8
-GLOBALNAME _imp__IoAttachDeviceToDeviceStack@8
-    dd      _IoAttachDeviceToDeviceStack@8
 
-extern      _PsGetCurrentProcessId@0
-GLOBALNAME _imp__PsGetCurrentProcessId@0
-    dd      _PsGetCurrentProcessId@0
+;;
+; @param 1  The fastcall name.
+; @param 2  The stdcall name.
+; @param 3  Byte size of arguments.
+%macro FastOrStdCallWrapper 3
+BEGINCODE
+extern _g_pfnrt %+ %1
+extern _g_pfnrt %+ %2
+BEGINPROC_EXPORTED $@ %+ %1 %+ @ %+ %3
+        mov     eax, [_g_pfnrt %+ %1]
+        cmp     eax, 0
+        jnz     .got_fast_call
+        mov     eax, .stdcall_wrapper
+        mov     [__imp_@ %+ %1 %+ @ %+ %3], eax
 
-extern      _ZwYieldExecution@0
-GLOBALNAME _imp__ZwYieldExecution@0
-    dd      _ZwYieldExecution@0
+.stdcall_wrapper:
+        push    ebp
+        mov     ebp, esp
+        push    edx
+        push    ecx
+        call    [_g_pfnrt %+ %2]
+        leave
+        ret
 
+.got_fast_call:
+        mov     [__imp_@ %+ %1 %+ @ %+ %3], eax
+        jmp     eax
+ENDPROC $@ %+ %1 %+ @ %+ %3
+
+BEGINDATA
+GLOBALNAME __imp_@ %+ %1 %+ @ %+ %3
+        dd       $@ %+ %1 %+ @ %+ %3
+%endmacro
+
+FastOrStdCallWrapper IofCompleteRequest, IoCompleteRequest, 8
+FastOrStdCallWrapper IofCallDriver, IoCallDriver, 8
+FastOrStdCallWrapper ObfDereferenceObject, ObDereferenceObject, 4
+FastOrStdCallWrapper KfAcquireSpinLock, KeAcquireSpinLock, 4
+FastOrStdCallWrapper KfReleaseSpinLock, KeReleaseSpinLock, 8
+FastOrStdCallWrapper KfLowerIrql, KeLowerIrql, 4
+FastOrStdCallWrapper KfRaiseIrql, KeRaiseIrql, 4
+
+
+BEGINCODE
+; LONG FASTCALL InterlockedExchange(LONG volatile *,LONG );
+BEGINPROC_EXPORTED $@InterlockedExchange@8
+        mov     eax, edx
+        xchg    [ecx], eax
+        ret
+
+BEGINDATA
+GLOBALNAME __imp_@InterlockedExchange@8
+        dd      $@InterlockedExchange@8
+
+
+BEGINDATA
+GLOBALNAME __imp__KeTickCount
+GLOBALNAME _KeTickCount
+        dd      0
+
+
