[Pkg-virtualbox-commits] [virtualbox] 01/03: Imported Upstream version 4.3.18-dfsg

Gianfranco Costamagna locutusofborg-guest at moszumanska.debian.org
Tue Oct 14 13:59:54 UTC 2014


This is an automated email from the git hooks/post-receive script.

locutusofborg-guest pushed a commit to branch master
in repository virtualbox.

commit f10ef2ab0f5a37acbc7a6685c6d1bb39dc2b6222
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date:   Tue Oct 14 15:43:23 2014 +0200

    Imported Upstream version 4.3.18-dfsg
---
 .dir-locals.el                                     |    7 +
 Config.kmk                                         |   15 +-
 Makefile.kmk                                       |  162 +-
 doc/manual/en_US/SDKRef.xml                        |    2 +-
 doc/manual/en_US/user_AdvancedTopics.xml           |   20 +
 doc/manual/en_US/user_Security.xml                 |    7 +
 doc/manual/user_ChangeLogImpl.xml                  |  150 +-
 include/VBox/err.h                                 |   23 +
 include/VBox/ostypes.h                             |    2 +
 include/VBox/vd-ifs.h                              |  134 +-
 include/iprt/asm.h                                 |    2 +-
 include/iprt/asn1.h                                |    3 +
 include/iprt/mangling.h                            |    4 +
 include/iprt/nt/nt.h                               |  398 +-
 include/iprt/path.h                                |   26 +
 include/iprt/string.h                              |   46 +
 .../Additions/common/VBoxGuest/VBoxGuest-win.cpp   |   11 +
 .../Additions/common/VBoxGuest/VBoxGuest-win.h     |    1 +
 src/VBox/Additions/linux/Makefile.kmk              |    2 +-
 src/VBox/Additions/x11/vboxvideo/vboxvideo.c       |    5 +-
 src/VBox/Debugger/DBGPlugInSolaris.cpp             |    4 +-
 src/VBox/Devices/Bus/DevPCI.cpp                    |    1 -
 src/VBox/Devices/EFI/DevSmc.cpp                    |    2 +
 src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd      |  Bin 1048576 -> 1048576 bytes
 src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd      |  Bin 1048576 -> 1048576 bytes
 src/VBox/Devices/Graphics/DevVGA_VBVA.cpp          |    3 +
 src/VBox/Devices/Makefile.kmk                      |   22 +-
 src/VBox/Devices/Network/DrvNAT.cpp                |   12 +-
 src/VBox/Devices/Network/slirp/slirp_dns.c         |    7 -
 src/VBox/Devices/PC/BIOS/ahci.c                    |    2 +-
 src/VBox/Devices/PC/BIOS/ata.c                     |    4 +-
 src/VBox/Devices/PC/BIOS/scsi.c                    |    2 +-
 src/VBox/Devices/PC/DevACPI.cpp                    |  237 +-
 src/VBox/Devices/PC/DevSMC.cpp                     |  630 ---
 src/VBox/Devices/Storage/DevAHCI.cpp               |   42 +-
 src/VBox/Devices/Storage/DrvDiskIntegrity.cpp      |   10 +
 src/VBox/Devices/USB/DevOHCI.cpp                   |   43 +-
 src/VBox/Devices/USB/DrvVUSBRootHub.cpp            |    6 +-
 src/VBox/Devices/USB/VUSBDevice.cpp                |  135 +-
 src/VBox/Devices/USB/VUSBInternal.h                |   59 +-
 src/VBox/Devices/USB/VUSBUrb.cpp                   |    4 +-
 .../Devices/USB/linux/USBProxyDevice-linux.cpp     |   24 +-
 src/VBox/Devices/build/VBoxDD.cpp                  |    2 -
 src/VBox/Devices/build/VBoxDD2.cpp                 |    5 -
 src/VBox/Devices/build/VBoxDD2.h                   |    3 -
 src/VBox/Devices/testcase/tstDeviceStructSize.cpp  |    2 +-
 .../Devices/testcase/tstDeviceStructSizeRC.cpp     |   23 +-
 .../Frontends/VBoxManage/VBoxManageGuestCtrl.cpp   |   30 +-
 src/VBox/Frontends/VirtualBox/Makefile.kmk         |    3 +-
 .../Frontends/VirtualBox/src/VBoxFBOverlay.cpp     |    2 +-
 .../VirtualBox/src/extensions/QIFileDialog.cpp     |   12 +-
 .../Frontends/VirtualBox/src/globals/UIDefs.cpp    |    3 +
 src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h |    6 +-
 .../VirtualBox/src/globals/VBoxGlobal.cpp          |  136 +-
 .../Frontends/VirtualBox/src/globals/VBoxGlobal.h  |    5 +-
 .../src/platform/darwin/VBoxUtils-darwin-cocoa.mm  |    6 +
 .../src/platform/darwin/VBoxUtils-darwin.cpp       |    5 +
 .../src/platform/darwin/VBoxUtils-darwin.h         |    2 +
 .../VirtualBox/src/runtime/UIMachineLogic.cpp      |    7 +-
 .../VirtualBox/src/runtime/UIMachineLogic.h        |    4 +-
 .../VirtualBox/src/runtime/UIMachineView.h         |    4 +-
 .../VirtualBox/src/runtime/UIMachineWindow.cpp     |    7 +
 .../VirtualBox/src/runtime/UIMachineWindow.h       |    5 +-
 .../Frontends/VirtualBox/src/runtime/UISession.cpp |    4 +-
 .../fullscreen/UIMachineLogicFullscreen.cpp        |  129 +-
 .../runtime/fullscreen/UIMachineLogicFullscreen.h  |   13 +-
 .../runtime/fullscreen/UIMachineViewFullscreen.cpp |    7 +-
 .../runtime/fullscreen/UIMachineViewFullscreen.h   |    4 +-
 .../fullscreen/UIMachineWindowFullscreen.cpp       |   70 +-
 .../runtime/fullscreen/UIMachineWindowFullscreen.h |    5 +
 .../src/runtime/normal/UIMachineViewNormal.cpp     |    9 +-
 .../src/runtime/normal/UIMachineViewNormal.h       |    4 +-
 .../src/runtime/normal/UIMachineWindowNormal.cpp   |   15 +
 .../runtime/seamless/UIMachineLogicSeamless.cpp    |   15 +-
 .../src/runtime/seamless/UIMachineLogicSeamless.h  |    4 +-
 .../src/runtime/seamless/UIMachineViewSeamless.cpp |    9 +-
 .../src/runtime/seamless/UIMachineViewSeamless.h   |    4 +-
 .../runtime/seamless/UIMachineWindowSeamless.cpp   |  103 +-
 .../src/runtime/seamless/UIMachineWindowSeamless.h |   24 +-
 .../src/widgets/UIApplianceEditorWidget.h          |    2 +-
 .../VirtualBox/src/widgets/UIMiniToolBar.cpp       |   52 +-
 .../VirtualBox/src/widgets/UIMiniToolBar.h         |   12 +
 .../wizards/exportappliance/UIWizardExportApp.cpp  |    2 +-
 src/VBox/HostDrivers/Support/Makefile.kmk          |    7 +
 src/VBox/HostDrivers/Support/SUPDrvIOC.h           |   17 +-
 src/VBox/HostDrivers/Support/SUPLib.cpp            |    5 +-
 src/VBox/HostDrivers/Support/SUPLibInternal.h      |   33 +-
 src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp |  270 +-
 .../HostDrivers/Support/SUPR3HardenedVerify.cpp    |   17 +-
 .../HostDrivers/Support/darwin/SUPLib-darwin.cpp   |    2 +-
 .../HostDrivers/Support/freebsd/SUPLib-freebsd.cpp |    2 +-
 .../HostDrivers/Support/linux/SUPLib-linux.cpp     |    2 +-
 src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp    |    2 +-
 .../HostDrivers/Support/solaris/SUPLib-solaris.cpp |    2 +-
 ...NtCreateSection-template-amd64-syscall-type-1.h |   78 -
 .../NtCreateSection-template-x86-syscall-type-1.h  |  286 --
 src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp    |  954 ++++-
 .../Support/win/SUPHardenedVerify-win.h            |   54 +-
 .../Support/win/SUPHardenedVerifyImage-win.cpp     |  354 +-
 .../Support/win/SUPHardenedVerifyProcess-win.cpp   |  233 +-
 src/VBox/HostDrivers/Support/win/SUPLib-win.cpp    |  137 +-
 .../Support/win/SUPR3HardenedMain-win.cpp          | 4060 +++++++++++++-------
 .../Support/win/SUPR3HardenedMainA-win.asm         |  117 +-
 .../Support/win/SUPR3HardenedMainImports-win.cpp   |  326 +-
 .../Support/win/SUPR3HardenedNoCrt-win.cpp         |  294 +-
 .../HostDrivers/Support/win/VBoxSupLib-win.cpp     |    2 +-
 .../Support/win/import-template-kernel32.h         |   12 +-
 .../Support/win/import-template-ntdll.h            |   46 +-
 .../SharedOpenGL/crserverlib/server_getshaders.c   |    2 +-
 src/VBox/Installer/win/Makefile.kmk                |   53 +-
 src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi      |    8 +-
 src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c      |    4 +-
 src/VBox/Main/cbinding/VBoxCAPIGlue.c              |    4 +-
 src/VBox/Main/cbinding/capiidl.xsl                 |   10 +-
 src/VBox/Main/cbinding/tstCAPIGlue.c               |    4 +-
 src/VBox/Main/include/ConsoleEvents.h              |  154 -
 src/VBox/Main/include/KeyboardImpl.h               |    4 -
 src/VBox/Main/include/MachineImpl.h                |    2 +-
 src/VBox/Main/include/MouseImpl.h                  |    1 -
 src/VBox/Main/src-client/GuestCtrlPrivate.cpp      |    5 +
 src/VBox/Main/src-server/ApplianceImplExport.cpp   |   22 +-
 src/VBox/Main/src-server/ApplianceImplImport.cpp   |    9 +-
 src/VBox/Main/src-server/MachineImpl.cpp           |   12 +-
 src/VBox/Main/src-server/MediumImpl.cpp            |    3 +-
 src/VBox/Main/xml/Settings.cpp                     |    6 +-
 src/VBox/NetworkServices/NAT/proxy.c               |    2 +-
 .../NetLib/VBoxNetPortForwardString.cpp            |    6 +-
 src/VBox/Runtime/Makefile.kmk                      |   15 +
 .../Runtime/common/asn1/asn1-efence-allocator.cpp  |   85 +
 src/VBox/Runtime/common/asn1/asn1-ut-string.cpp    |    6 +-
 src/VBox/Runtime/common/crypto/store-inmem.cpp     |    6 +-
 src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp        |    1 +
 src/VBox/Runtime/common/ldr/ldrMemory.cpp          |    2 +-
 src/VBox/Runtime/common/ldr/ldrPE.cpp              |    2 +-
 src/VBox/Runtime/common/string/strformat.cpp       |    2 +-
 src/VBox/Runtime/common/string/utf-16.cpp          |   14 +
 src/VBox/Runtime/common/time/time.cpp              |    2 +-
 src/VBox/Runtime/generic/RTPathAbs-generic.cpp     |  358 ++
 .../generic/RTPathGetCurrentDrive-generic.cpp      |  106 +
 .../generic/RTPathGetCurrentOnDrive-generic.cpp    |   84 +
 src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c   |    9 +-
 src/VBox/Runtime/r3/memsafer-r3.cpp                |   10 +
 src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp           |   10 +-
 src/VBox/Runtime/r3/nt/fs-nt.cpp                   |   24 +-
 src/VBox/Runtime/r3/nt/internal-r3-nt.h            |   78 +-
 src/VBox/Runtime/r3/nt/pathint-nt.cpp              |  237 +-
 src/VBox/Runtime/r3/posix/path-posix.cpp           |  218 --
 .../Runtime/r3/win/RTSystemQueryOSInfo-win.cpp     |    1 +
 src/VBox/Runtime/r3/win/init-win.cpp               |    3 +
 src/VBox/Runtime/r3/win/internal-r3-win.h          |    1 +
 src/VBox/Runtime/r3/win/ntdll-mini-implib.def      |   27 +-
 src/VBox/Runtime/r3/win/path-win.cpp               |   22 +-
 src/VBox/Runtime/testcase/tstRTPath.cpp            |    2 +-
 src/VBox/Storage/VHD.cpp                           |    2 +-
 src/VBox/Storage/testcase/BuiltinTests.h           |   41 +
 src/VBox/Storage/testcase/Makefile.kmk             |   80 +-
 src/VBox/Storage/testcase/VDMemDisk.cpp            |    1 +
 src/VBox/Storage/testcase/VDScript.cpp             |  393 +-
 src/VBox/Storage/testcase/VDScript.h               |   69 +
 src/VBox/Storage/testcase/VDScriptAst.cpp          |   18 +-
 src/VBox/Storage/testcase/VDScriptAst.h            |  129 +
 src/VBox/Storage/testcase/tstVDCompact.vd          |   30 +-
 src/VBox/Storage/testcase/tstVDCopy.vd             |   18 +-
 src/VBox/Storage/testcase/tstVDDiscard.vd          |    8 +-
 src/VBox/Storage/testcase/tstVDIo.cpp              |  233 +-
 src/VBox/Storage/testcase/tstVDIo.vd               |   16 +-
 src/VBox/Storage/testcase/tstVDMultBackends.vd     |   60 +
 src/VBox/Storage/testcase/tstVDResize.vd           |   21 +-
 src/VBox/Storage/testcase/tstVDShareable.vd        |    9 +-
 src/VBox/VMM/VMMAll/IOMAllMMIO.cpp                 |    2 +-
 src/VBox/VMM/VMMR0/HMSVMR0.cpp                     |   17 +-
 src/VBox/VMM/VMMR0/HMVMXR0.cpp                     |   22 +-
 src/VBox/VMM/VMMR3/MMPagePool.cpp                  |    2 +-
 src/VBox/VMM/VMMR3/PGMPhys.cpp                     |    2 +-
 src/VBox/VMM/VMMR3/PGMPool.cpp                     |    4 +-
 src/VBox/VMM/VMMR3/PGMSavedState.cpp               |    6 +-
 src/VBox/VMM/VMMR3/STAM.cpp                        |    3 +-
 src/VBox/VMM/testcase/tstAnimate.cpp               |    2 +-
 src/bldprogs/VBoxCPP.cpp                           |    4 +-
 src/bldprogs/scmdiff.cpp                           |    2 +-
 180 files changed, 8641 insertions(+), 4529 deletions(-)

diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..08dca97
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,7 @@
+;;; Directory Local Variables
+;;; See Info node `(emacs) Directory Variables' for more information.
+
+((c++-mode
+  (indent-tabs-mode))
+ (c-mode
+  (indent-tabs-mode)))
diff --git a/Config.kmk b/Config.kmk
index 26405c1..67b8f87 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -208,7 +208,7 @@ VBOX_VERSION_MINOR = 3
 # This is the current build number. It should be increased every time we publish a
 # new build. The define is available in every source file. Only even build numbers
 # will be published, odd numbers are set during development.
-VBOX_VERSION_BUILD = 16
+VBOX_VERSION_BUILD = 18
 # The raw version string. This *must not* contain any other information/fields than
 # major, minor and build revision (as it is now) -- also will be used for host/guest version
 # comparison.
@@ -641,6 +641,10 @@ endif
 ifeq ($(KBUILD_TARGET),win)
  VBOX_WITH_MMR = 1
 endif
+# Enables use of merge modules in the windows installer. This will increase
+# the overall installer size significantly because merge modules are not able
+# to use a common .cab file to reduce their size.
+#VBOX_WITH_MSM_INSTALL = 1
 ## @}
 
 
@@ -2597,7 +2601,11 @@ ifdef VBOX_SIGNING_MODE
   else if1of ($(VBOX_SIGNING_MODE), release development)
    VBOX_CERTIFICATE_SUBJECT_NAME ?= Oracle Corporation
    VBOX_CERTIFICATE_SUBJECT_NAME_ARGS ?= /n "$(VBOX_CERTIFICATE_SUBJECT_NAME)" /a
-   VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/MSCV-VSClass3.cer
+   if defined(VBOX_ONLY_ADDITIONS) || defined(VBOX_ONLY_EXTPACKS)
+    VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/VeriSign Class 3 Public Primary Certification Authority - G5.cer
+   else
+    VBOX_CROSS_CERTIFICATE_FILE ?= $(VBOX_PATH_SELFSIGN)/MSCV-VSClass3.cer
+   endif
    VBOX_CROSS_CERTIFICATE_FILE_ARGS ?= /ac "$(VBOX_CROSS_CERTIFICATE_FILE)"
    VBOX_TSA_URL ?= http://timestamp.verisign.com/scripts/timestamp.dll
    VBOX_TSA_URL_ARGS ?= /t "$(VBOX_TSA_URL)"
@@ -5690,7 +5698,7 @@ endif
 SVN                    ?= svn$(HOSTSUFF_EXE)
 VBOX_SVN_REV_KMK        = $(PATH_OUT)/revision.kmk
 ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,,  $Rev: 95972 $  )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,,  $Rev: 96516 $  )
  VBOX_SVN_DEP          := $(firstword $(wildcard $(PATH_ROOT)/.svn/wc.db $(abspath $(PATH_ROOT)/../.svn/wc.db) $(abspath $(PATH_ROOT)/../../.svn/wc.db) $(PATH_ROOT)/.svn/entries))
  ifeq ($(which $(SVN)),)
   VBOX_SVN_DEP         :=
@@ -5842,3 +5850,4 @@ st stat status:
 quick:
 	$(MAKE) VBOX_QUICK=1
 
+
diff --git a/Makefile.kmk b/Makefile.kmk
index 4f326b4..b39df14 100644
--- a/Makefile.kmk
+++ b/Makefile.kmk
@@ -174,6 +174,11 @@ else
    qt4-bin_SOURCES = \
    	$(foreach qtmod,$(VBOX_QT4_MOD_NAMES),$(call VBOX_RE_SIGN_DLL_FN,qt4-bin,$(VBOX_PATH_QT4_LIB)/$(qtmod)4$(SUFF_DLL))) \
    	$(call VBOX_RE_SIGN_DLL_FN,qt4-bin,$(VBOX_PATH_QT4)/plugins/accessible/qtaccessiblewidgets4$(SUFF_DLL))=>accessible/qtaccessiblewidgets4$(SUFF_DLL)
+   ifdef VBOX_WITH_QT_PDBS
+    qt4-bin_SOURCES += \
+    	$(foreach qtmod,$(VBOX_QT4_MOD_NAMES),$(VBOX_PATH_QT4_LIB)/$(qtmod)4.pdb) \
+    	$(VBOX_PATH_QT4)/plugins/accessible/qtaccessiblewidgets4.pdb=>accessible/qtaccessiblewidgets4.pdb
+   endif
   else
    INSTALLS += qt4-bin
    qt4-bin_MODE = 755
@@ -804,9 +809,9 @@ VBOX_RSYNC_IN_FN = rsync -a -v --delete --delete-excluded --prune-empty-dirs \
 #
 # VM IP addresses.
 #
-VBOX_BLD_VM_LNX_X86_IP       := 192.168.27.2
+VBOX_BLD_VM_LNX_IP           := 192.168.27.2
+VBOX_BLD_VM_LNX_X86_IP       := 192.168.27.11
 VBOX_BLD_VM_LNX_AMD64_IP     := 192.168.27.12
-VBOX_BLD_VM_LNX_NEW_X86_IP   := 192.168.27.11
 VBOX_BLD_VM_OS2_IP           := 192.168.27.3
 VBOX_BLD_VM_SOLARIS_IP       := 192.168.27.4
 VBOX_BLD_VM_DARWIN_X86_IP    := 192.168.27.5
@@ -825,7 +830,7 @@ if 0
  VBOX_BLD_VM_MSG_BEGIN = $(call MSG_L1,Building $1.)
  VBOX_BLD_VM_MSG_END__ =
 else
- VBOX_BLD_VM_MSG_BEGIN = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Building $1.
+ VBOX_BLD_VM_MSG_BEGIN = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Start building $1.
  VBOX_BLD_VM_MSG_END__ = @echo `date "+%Y-%m-%dT%H:%M:%S"` - Done building $1.
 endif
 
@@ -861,13 +866,14 @@ additions-build: \
 	additions-build-solaris.amd64 \
 	additions-build-solaris.x86 \
 	additions-build-os2.x86 \
-	additions-build-linux.x86.combined
+	additions-build-linux
 
 additions-build-rsync-into-vms: \
 		additions-build-solaris.rsync-into-vm \
-		additions-build-os2.rsync-into-vm
+		additions-build-os2.rsync-into-vm \
+		additions-build-linux.rsync-into-vm
 	$(call MSG_L1,Rsynced the sources + tools into the VMs.)
-#.NOTPARALLEL: additions-build-rsync-into-vms
+.NOTPARALLEL: additions-build-rsync-into-vms
 
 
 VBOX_ADDITIONS_BUILD.amd64 = VBOX_ONLY_ADDITIONS=1 VBOX_WITHOUT_ADDITIONS_ISO=1 \
@@ -898,9 +904,9 @@ ifeq ($(KBUILD_TARGET),win)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) all $(VBOX_ADD_HOST_BUILD_TWEAK)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) packing
 else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Windows/amd64 additions)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Windows/amd64 additions build+pack)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_WIN_AMD64_IP) " echo $@ && cd e:/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing "
-	$(call VBOX_BLD_VM_MSG_END__,Windows/amd64 additions)
+	$(call VBOX_BLD_VM_MSG_END__,Windows/amd64 additions build+pack)
 endif
 
 additions-build-win.x86:
@@ -908,9 +914,9 @@ ifeq ($(KBUILD_TARGET),win)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing
 else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Windows/x86 additions)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Windows/x86 additions build.pack)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_WIN_X86_IP) " echo $@ && cd e:/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh kmk $(VBOX_ADDITIONS_BUILD.x86) all packing"
-	$(call VBOX_BLD_VM_MSG_END__,Windows/x86 additions)
+	$(call VBOX_BLD_VM_MSG_END__,Windows/x86 additions build+pack)
 endif
 
 # ASSUMES the 64-bit edition are built first. This also serializes VM access.
@@ -933,18 +939,18 @@ additions-build-solaris.rsync-into-vm:
 		. $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
 
 additions-build-solaris.build-it: additions-build-solaris.rsync-into-vm
-	$(call VBOX_BLD_VM_MSG_BEGIN,Solaris/amd64 additions)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Solaris/amd64 additions build+pack)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/amd64 && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing"
-	$(call VBOX_BLD_VM_MSG_END__,Solaris/amd64 additions)
-	$(call VBOX_BLD_VM_MSG_BEGIN,Solaris/x86 additions)
+	$(call VBOX_BLD_VM_MSG_END__,Solaris/amd64 additions build+pack)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Solaris/x86 additions build+pack)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/x86   && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_SOLARIS_GUEST_PACKAGE=1"
-	$(call VBOX_BLD_VM_MSG_END__,Solaris/x86 additions)
+	$(call VBOX_BLD_VM_MSG_END__,Solaris/x86 additions build+pack)
 
 additions-build-solaris.rsync-out-of-vm: additions-build-solaris.build-it
 	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/solaris.x86 out/
 	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_SOLARIS_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/solaris.amd64 out/
 
-#.NOTPARALLEL: additions-build-solaris.rsync-into-vm
+.NOTPARALLEL: additions-build-solaris.rsync-into-vm
 .PHONY:       additions-build-solaris.rsync-into-vm additions-build-solaris.rsync-out-of-vm additions-build-solaris.build-it
 
 additions-build-solaris.amd64: additions-build-solaris.rsync-out-of-vm
@@ -968,14 +974,14 @@ additions-build-os2.rsync-into-vm:
 		. rsync://vbox@$(VBOX_BLD_VM_OS2_IP)/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
 
 additions-build-os2.build-it: additions-build-os2.rsync-into-vm
-	$(call VBOX_BLD_VM_MSG_BEGIN,OS/2 additions)
+	$(call VBOX_BLD_VM_MSG_BEGIN,OS/2 additions build+pack)
 	$(VBOX_KMK_TIME) rsh -l vbox $(VBOX_BLD_VM_OS2_IP) "cd e:\\tinderbox\\$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && e: && kbuild\\bin\\os2.x86\\kmk_ash tools\\env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing"
-	$(call VBOX_BLD_VM_MSG_END__,OS/2 additions)
+	$(call VBOX_BLD_VM_MSG_END__,OS/2 additions build+pack)
 
 additions-build-os2.rsync-out-of-vm: additions-build-os2.build-it
 	$(VBOX_KMK_TIME) rsync -v -a --delete rsync://vbox@$(VBOX_BLD_VM_OS2_IP)/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/os2.x86 ./out
 
-#.NOTPARALLEL: additions-build-os2.rsync-into-vm
+.NOTPARALLEL: additions-build-os2.rsync-into-vm
 .PHONY:       additions-build-os2.rsync-into-vm additions-build-os2.rsync-out-of-vm additions-build-os2.build-it
 
 additions-build-os2.x86: additions-build-os2.rsync-out-of-vm
@@ -986,48 +992,56 @@ additions-build-os2.x86:
 # Dummy
 endif
 
-additions-build-linux.amd64:   $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
+ifeq ($(KBUILD_TARGET),linux)
+additions-build-linux.amd64:
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) all $(VBOX_ADD_HOST_BUILD_TWEAK)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.amd64) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
+
+additions-build-linux.x86:
+	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
+
+additions-build-linux: additions-build-linux.x86 additions-build-linux.amd64
+	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
+	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1
 else
+additions-build-linux.rsync-into-vm:
+	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,linux,*) \
+		'--exclude=src/VBox/Additions/WINNT/**' \
+		'--exclude=src/VBox/Frontends/**' \
+		'--exclude=src/VBox/VMM/**' \
+		. $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)
+
+additions-build-linux.build-it: additions-build-linux.rsync-into-vm
  ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING
 	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions/greeter)
-	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) "echo $@ && dchroot -c ubuntu-11.10-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux2.amd64/$(KBUILD_TYPE) VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && dchroot -c ubuntu-11.10-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.amd64/$(KBUILD_TYPE)/greeter VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
 	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions/greeter)
  endif
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions)
-	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)"
-	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions)
-endif
-
-additions-build-linux.x86:   $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
-	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
-	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1
-else
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 additions build+pack)
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.amd64) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
+	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 additions build+pack)
  ifdef VBOX_WITH_LIGHTDM_GREETER_PACKING
 	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions/greeter)
-	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) "echo $@ && dchroot -c ubuntu-11.10-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && BUILD_PLATFORM_ARCH=x86 tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux2.x86/$(KBUILD_TYPE) VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c ubuntu-11.10-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && BUILD_PLATFORM_ARCH=x86 tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) PATH_OUT=/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.x86/$(KBUILD_TYPE)/greeter VBOX_WITH_LIGHTDM_GREETER=1 vbox-greeter\""'
 	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions/greeter)
  endif
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions)
-	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
-	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions)
-endif
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions build+pack)
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITHOUT_LINUX_GUEST_PACKAGE=1 VBOX_WITH_LIGHTDM_GREETER_PACKING=$(VBOX_WITH_LIGHTDM_GREETER_PACKING)\""'
+	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions build+pack)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions combine)
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1\""'
+	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions combine)
 
-# Combined Linux Additions .run package.  This depends on the archives
-# created during packing by the architecture-specific builds.
-additions-build-linux.x86.combined:   $(VBOX_ADDITIONS_BUILD_WIN_HOST_FIRST) additions-build-linux.x86 additions-build-linux.amd64
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
-	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) all $(VBOX_ADD_HOST_BUILD_TWEAK)
-	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_ADDITIONS_BUILD.x86) packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1
-else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 additions)
-	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_ADDITIONS_BUILD.x86) all packing VBOX_WITH_COMBINED_LINUX_GUEST_PACKAGE=1\""'
-	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 additions)
-endif
+additions-build-linux.rsync-out-of-vm: additions-build-linux.build-it
+	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.x86 out/
+	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_ADDITIONS_BUILD_SUBDIRNAME)/out/linux.amd64 out/
+
+.NOTPARALLEL: additions-build-linux.rsync-into-vm
+.PHONY:       additions-build-linux.rsync-into-vm additions-build-linux.rsync-out-of-vm additions-build-linux.build-it
 
+additions-build-linux: additions-build-linux.rsync-out-of-vm
+endif
 
 additions-packing:
 	+ $(KMK) VBOX_ONLY_ADDITIONS=1 \
@@ -1051,6 +1065,7 @@ additions-packing:
 	additions-build-solaris.amd64 \
 	additions-build-solaris.x86 \
 	additions-build-os2.x86 \
+	additions-build-linux \
 	additions-build-linux.amd64 \
 	additions-build-linux.x86 \
 	additions-build-linux.x86.combined \
@@ -1084,8 +1099,7 @@ extpacks-build: \
 	extpacks-build-win.x86 \
 	extpacks-build-solaris.amd64 \
 	extpacks-build-os2.x86 \
-	extpacks-build-linux.amd64 \
-	extpacks-build-linux.x86 \
+	extpacks-build-linux \
 	extpacks-build-darwin.amd64 \
 	extpacks-build-darwin.x86 \
 	extpacks-build-freebsd.amd64 \
@@ -1161,22 +1175,35 @@ extpacks-build-os2.x86:
 #	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_OS2_IP) " cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) "
 #endif
 
+ifeq ($(KBUILD_TARGET),linux)
 extpacks-build-linux.amd64:   $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_EXTPACKS_BUILD.amd64) all $(VBOX_EXTPACKS_HOST_BUILD_TWEAK)
-else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 extension packs)
-	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
-	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 extension packs)
-endif
 
 extpacks-build-linux.x86:   $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
-ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_EXTPACKS_BUILD.x86) all $(VBOX_EXTPACKS_HOST_BUILD_TWEAK)
+
+extpacks-build-linux: extpacks-build-linux.x86 extpacks-build-linux.amd64
 else
+# Serialize 32-bit and 64-bit ASSUMING the same VM builds both.
+extpacks-build-linux.rsync-into-vm: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
+	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,linux,*) . $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+
+extpacks-build-linux.build-it: extpacks-build-linux.rsync-into-vm
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 extension packs)
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all\""'
+	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 extension packs)
 	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 extension packs)
-	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all"
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@ && linux32 dchroot -c debian-4.0-i386 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all\""'
 	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 extension packs)
+
+extpacks-build-linux.rsync-out-of-vm: extpacks-build-linux.build-it
+	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/linux.x86 out/
+	$(VBOX_KMK_TIME) rsync -a --delete $(VBOX_BLD_VM_LNX_IP):/mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/linux.amd64 out/
+
+#.NOTPARALLEL: extpacks-build-linux.rsync-into-vm
+.PHONY:       extpacks-build-linux.rsync-out-of-vm extpacks-build-linux.rsync-into-vm extpacks-build-linux.build-it
+
+extpacks-build-linux: extpacks-build-linux.rsync-out-of-vm
 endif
 
 extpacks-build-freebsd.amd64: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
@@ -1231,6 +1258,7 @@ extpacks-packing:
 	extpacks-build-win.amd64 \
 	extpacks-build-solaris.amd64 \
 	extpacks-build-os2.x86 \
+	extpacks-build-linux \
 	extpacks-build-linux.amd64 \
 	extpacks-build-linux.x86 \
 	extpacks-build-freebsd.amd64 \
@@ -1384,18 +1412,20 @@ testsuite-build-linux.amd64:   $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
 ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.amd64)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.amd64) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
 else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 testsuite)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 Validation Kit)
+	#$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all\""'
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_LNX_AMD64_IP) " echo $@ && cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all"
-	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 testsuite)
+	$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 Validation Kit)
 endif
 
 testsuite-build-linux.x86:   $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
 ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),linux.x86)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.x86) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
 else
-	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 testsuite)
-	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_NEW_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
-	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 testsuite)
+	$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 Validation Kit)
+	#$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_X86_IP) "echo $@ && linux32 dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
+	$(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_X86_IP) "echo $@ && dchroot -c rhel3-i386 \"cd /mnt/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all\""'
+	$(call VBOX_BLD_VM_MSG_END__,Linux/x86 Validation Kit)
 endif
 
 testsuite-build-freebsd.amd64:   $(VBOX_TESTSUITE_BUILD_WIN_HOST_FIRST)
@@ -1421,9 +1451,9 @@ ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),darwin.amd64)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.amd64) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
 else
 	$(call VBOX_BLD_VM_MSG_BEGIN,Darwin/amd64 testsuite)
-	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,amd64) . $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,amd64) . $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_DARWIN_AMD64_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.amd64) all"
-	$(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/darwin.amd64 out/
+	$(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)/out/darwin.amd64 out/
 	$(call VBOX_BLD_VM_MSG_END__,Darwin/amd64 testsuite)
 endif
 
@@ -1432,9 +1462,9 @@ ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),darwin.x86)
 	+ $(VBOX_KMK_TIME) $(KMK) $(VBOX_TESTSUITE_BUILD.x86) all $(VBOX_TESTSUITE_HOST_BUILD_TWEAK)
 else
 	$(call VBOX_BLD_VM_MSG_BEGIN,Darwin/x86 testsuite)
-	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,x86) . $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
+	$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,x86) . $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)
 	$(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_DARWIN_X86_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_TESTSUITE_BUILD.x86) all"
-	$(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/darwin.x86 out/
+	$(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_X86_IP):/Users/vbox/tinderbox/$(VBOX_TESTSUITE_BUILD_SUBDIRNAME)/out/darwin.x86 out/
 	$(call VBOX_BLD_VM_MSG_END__,Darwin/x86 testsuite)
 endif
 
diff --git a/doc/manual/en_US/SDKRef.xml b/doc/manual/en_US/SDKRef.xml
index 8f773c5..d95c475 100644
--- a/doc/manual/en_US/SDKRef.xml
+++ b/doc/manual/en_US/SDKRef.xml
@@ -1975,7 +1975,7 @@ g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para>
           their other functionality:<screen>SAFEARRAY *psa = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc();
 ULONG *pData;
 ULONG cElements;
-IArrayDemo_ReturnArray(pThis, ComSafeArrayAsOutParam(psa));
+IArrayDemo_ReturnArray(pThis, ComSafeArrayAsOutTypeParam(psa, ULONG));
 g_pVBoxFuncs->pfnSafeArrayCopyOutParamHelper((void **)&pData, &cElements, VT_I4, psa);
 g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para>
 
diff --git a/doc/manual/en_US/user_AdvancedTopics.xml b/doc/manual/en_US/user_AdvancedTopics.xml
index 92dd179..6b81646 100644
--- a/doc/manual/en_US/user_AdvancedTopics.xml
+++ b/doc/manual/en_US/user_AdvancedTopics.xml
@@ -2889,6 +2889,26 @@ VBoxManage setextradata "VM name" VBoxInternal2/CoreDumpLive 1</screen>At
 
     </sect2>
 
+    <sect2 id="legacy-fullscreen-mode">
+      <title>Requesting legacy full-screen mode</title>
+
+      <para>
+        As of version 4.3.16, VirtualBox uses special window manager facilities to switch
+        a multi-screen machine to full-screen on a multi-monitor host system. However,
+        not all window managers provide these facilities correctly, so VirtualBox can be
+        told to use the old method of switching to full-screen mode instead using the command:
+      </para>
+      <para><screen>VBoxManage setextradata global GUI/Fullscreen/LegacyMode true</screen></para>
+
+      <para>
+        You can go back to the new method using the command:
+      </para>
+      <para><screen>VBoxManage setextradata global GUI/Fullscreen/LegacyMode</screen></para>
+
+      <para>This is a global setting.</para>
+
+    </sect2>
+
   </sect1>
 
   <sect1 id="vboxwebsrv-daemon">
diff --git a/doc/manual/en_US/user_Security.xml b/doc/manual/en_US/user_Security.xml
index 9eab619..61f0c60 100644
--- a/doc/manual/en_US/user_Security.xml
+++ b/doc/manual/en_US/user_Security.xml
@@ -352,6 +352,13 @@
           IPsec), or use encrypted protocols in the guest network (such as
           SSH). The security properties are similar to bridged Ethernet.</para>
         </listitem>
+
+        <listitem>
+          <para>Because of shortcomings in older Windows versions, using
+          VirtualBox on Windows versions older than Vista with Service Pack 1
+          is not recommended.</para>
+        </listitem>
+
       </itemizedlist></para>
     </sect2>
 
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index 3f2b5c6..8fa1c7b 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -1,6 +1,124 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
   <sect1>
+    <title>Version 4.3.18 (2014-10-10)</title>
+
+    <para>This is a maintenance release. The following items were fixed and/or
+      added:</para>
+
+    <itemizedlist>
+
+      <listitem>
+        <para>VMM: fixed a potential misbehavior after restoring the A20 state
+          from a saved state</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: fixed full-screen mode mini-toolbar related regressions
+          for different platforms and window managers (bug #13369)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: X11: fixed full-screen mode Unity panels quirk caused by
+          mini-toolbar code changes in last release (bug #13365)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: X11: added possibility to use legacy full-screen mode
+          as the new one can cause multi-screen issues under Unity, see
+          <xref linkend="legacy-fullscreen-mode" xreflabel="here"/> (bug #13365)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: Mac OS X: fixed full-screen mode artifact causing black screen
+           when 3D acceleration was enabled on 10.10 Yosemite hosts (bug #13448)</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: Mac OS X: fixed regression in user-space swiping from/to
+          VBox in full-screen mode</para>
+      </listitem>
+
+      <listitem>
+        <para>GUI: Mac OS X: fixed issue with switching to VBox in full-screen
+          mode through Alt+Tab and Mission Control</para>
+      </listitem>
+
+      <listitem>
+        <para>Storage: fixed data corruption when resizing huge VHD images under
+          certain circumstances (bug #11960)</para>
+      </listitem>
+
+      <listitem>
+        <para>Storage: fixed a rare hang during startup when the BIOS enumerates the
+          storage devices attached to the SATA controller</para>
+      </listitem>
+
+      <listitem>
+        <para>Storage: follow the spec with AHCI interrupt acknowledge (bug #13474)</para>
+      </listitem>
+
+      <listitem>
+        <para>Storage: fixed broken iSCSI authentication (4.3.14 regression, bugs #13386,
+          #13435)</para>
+      </listitem>
+
+      <listitem>
+        <para>NAT Network: properly parse port forwarding rules to allow UDP
+          rules</para>
+      </listitem>
+
+      <listitem>
+        <para>USB: fixed a crash on Linux hosts with older Linux kernels (bug #13400) and
+          several other fixes</para>
+      </listitem>
+
+      <listitem>
+        <para>ACPI: fixed ACPI timer anomalies (bug #12076)</para>
+      </listitem>
+
+      <listitem>
+        <para>Guest Control: fixed a memory leak (bug #13434)</para>
+      </listitem>
+
+      <listitem>
+        <para>Main: when removing a VM, do also remove the VBoxStartup.log file
+          which might exist on Windows hosts (bug #13478)</para>
+      </listitem>
+
+      <listitem>
+        <para>Windows hosts: fixed more startup problems on certain Windows hosts due
+          to conflicts with anti-virus software; better error reporting
+          (4.3.14 regression; bug #13187)</para>
+      </listitem>
+
+      <listitem>
+        <para>Windows hosts: propagate the process startup information to the child
+          process (4.3.14 regression; bug #13243)</para>
+      </listitem>
+
+      <listitem>
+        <para>Mac OS X hosts: don't force using the discrete GPU (bug #11111)</para>
+      </listitem>
+
+      <listitem>
+        <para>Windows Additions: some Windows 10 tweaks</para>
+      </listitem>
+
+      <listitem>
+        <para>X11 guests: fix a bug handling video driver display properties
+           which prevented GNOME Shell on Fedora 21 from starting</para>
+      </listitem>
+
+      <listitem>
+        <para>Linux hosts / guests: fixed a few remaining warnings in the kernel
+          log if memory allocation fails (bug #11171)</para>
+      </listitem>
+
+    </itemizedlist>
+  </sect1>
+
+  <sect1>
     <title>Version 4.3.16 (2014-09-09)</title>
 
     <para>This is a maintenance release. The following items were fixed and/or
@@ -136,7 +254,7 @@
 
       <listitem>
         <para>Windows hosts: fixed startup problems on certain Windows hosts due
-          to conflicts with anti-virus software (4.3.14 regression, bug #13187)</para>
+          to conflicts with anti-virus software (4.3.14 regression; bug #13187)</para>
       </listitem>
 
       <listitem>
@@ -420,7 +538,7 @@
 
       <listitem>
         <para>GUI: fixed crash under rare conditions on entering/exiting
-          fullscreen/seamless mode</para>
+          full-screen/seamless mode</para>
       </listitem>
 
       <listitem>
@@ -920,7 +1038,7 @@
       </listitem>
 
       <listitem>
-        <para>GUI: fixed deleting of inaccessible VMs (4.3 regression, bug
+        <para>GUI: fixed deleting of inaccessible VMs (4.3 regression; bug
           #12205)</para>
       </listitem>
 
@@ -976,7 +1094,7 @@
 
       <listitem>
         <para>Solaris hosts: fixed accessing the host driver from non-global zones
-          (4.3 regression, bug #12271)</para>
+          (4.3 regression; bug #12271)</para>
       </listitem>
 
     </itemizedlist>
@@ -1801,7 +1919,7 @@
 
       <listitem>
         <para>Snapshots: fixed a bug which could result in lost medium attachments
-          (4.2.18 regression, bug #11750)</para>
+          (4.2.18 regression; bug #11750)</para>
       </listitem>
 
       <listitem>
@@ -2553,7 +2671,7 @@
 
       <listitem>
         <para>Storage: fixed non working online merging of snapshots
-          (4.2.6 regression, bug #11359)</para>
+          (4.2.6 regression; bug #11359)</para>
       </listitem>
 
       <listitem>
@@ -2872,7 +2990,7 @@
 
       <listitem>
         <para>GUI: fixed validation warning on global settings / proxy page
-          (4.2.2 regression, bug #11089)</para>
+          (4.2.2 regression; bug #11089)</para>
       </listitem>
 
       <listitem>
@@ -3165,7 +3283,7 @@
       <listitem>
         <para>VMM: fixed a potential host crash triggered by shutting down a VM
           when another VM was running (only affected 32-bit hosts and 64-bit OS X hosts,
-          4.1 regression, bug #9897)</para>
+          4.1 regression; bug #9897)</para>
       </listitem>
 
       <listitem>
@@ -3492,7 +3610,7 @@
 
       <listitem>
         <para>Windows Additions: fixed guest driver crash of VBoxSF in certain
-          cases (4.1.10 regression, bug #10408)</para>
+          cases (4.1.10 regression; bug #10408)</para>
       </listitem>
 
       <listitem>
@@ -7981,7 +8099,7 @@
 
       <listitem>
         <para>Linux Additions: make the mouse driver work on Debian 5.0.3 guests
-           again (3.1.2 regression, bug #5832)</para>
+           again (3.1.2 regression; bug #5832)</para>
       </listitem>
 
       <listitem>
@@ -8999,7 +9117,7 @@
 
       <listitem>
         <para>BIOS: fixed a bug that caused the OS/2 boot manager to fail
-          (2.1.0 regression, bug #3911)</para>
+          (2.1.0 regression; bug #3911)</para>
       </listitem>
 
       <listitem>
@@ -9202,7 +9320,7 @@
 
       <listitem>
         <para>USB: fixed a bug that may have rendered USB device filter settings
-          inactive (3.0.2 regression, bug #4668)</para>
+          inactive (3.0.2 regression; bug #4668)</para>
       </listitem>
 
       <listitem>
@@ -9880,7 +9998,7 @@
 
       <listitem>
         <para>Windows Additions: fixed mouse pointer integration of some
-          Windows guests (2.2.0 regression, bug #3734)</para>
+          Windows guests (2.2.0 regression; bug #3734)</para>
       </listitem>
 
       <listitem>
@@ -9924,7 +10042,7 @@
       </listitem>
 
       <listitem>
-        <para>GUI: HostKey could not be changed (2.2.0 regression,
+        <para>GUI: HostKey could not be changed (2.2.0 regression;
           bug #3689)</para>
       </listitem>
 
@@ -9961,7 +10079,7 @@
 
       <listitem>
         <para>Networking: fixed a deadlock caused by the PCnet network device
-          emulation (2.2.0 regression, bug #3676)</para>
+          emulation (2.2.0 regression; bug #3676)</para>
       </listitem>
 
       <listitem>
@@ -10668,7 +10786,7 @@
 
       <listitem>
         <para>SATA: raw disk partitions were not recognized
-          (2.1.0 regression, Windows host only, bug #2778)</para>
+          (2.1.0 regression; Windows host only, bug #2778)</para>
       </listitem>
 
       <listitem>
diff --git a/include/VBox/err.h b/include/VBox/err.h
index d15b2a8..5bd8993 100644
--- a/include/VBox/err.h
+++ b/include/VBox/err.h
@@ -1762,6 +1762,8 @@
 /** The CSRSS instance associated with the client process could not be
  * located. */
 #define VERR_SUPDRV_CSRSS_NOT_FOUND                 (-3741)
+/** Type error opening the ApiPort LPC object. */
+#define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE         (-3742)
 /** @} */
 
 
@@ -2495,6 +2497,27 @@
 #define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER  (-5667)
 /** The image is outside the expected range. */
 #define VERR_SUP_VP_IMAGE_TOO_BIG                   (-5668)
+/** Stub process not found so it cannot be revalidated when vboxdrv is opened
+ * by the VM process. */
+#define VERR_SUP_VP_STUB_NOT_FOUND                  (-5669)
+/** Error openeing the stub process for revalidation when vboxdrv is opened by
+ *  the VM process. */
+#define VERR_SUP_VP_STUB_OPEN_ERROR                 (-5670)
+/** Stub process thread not found during revalidation upon vboxdrv opening by
+ * the VM process. */
+#define VERR_SUP_VP_STUB_THREAD_NOT_FOUND           (-5671)
+/** Error opening the stub process thread for revalidation when vboxdrv is
+ * opened by the VM process. */
+#define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR          (-5672)
+/** Process Purification Failure: NtAllocateVirtualMemory failed to get us
+ * suitable replacement memory for a chunk of executable memory that
+ * shouldn't be present in our process.  (You will only see this message if you
+ * got potentially fatally buggy anti-virus software installed.) */
+#define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED   (-5673)
+/** Error getting the file mode. */
+#define VERR_SUP_VP_FILE_MODE_ERROR                 (-5674)
+/** Error creating an event semaphore for used with asynchronous reads. */
+#define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED      (-5675)
 
 /** @} */
 
diff --git a/include/VBox/ostypes.h b/include/VBox/ostypes.h
index 890c2be..c197fe3 100644
--- a/include/VBox/ostypes.h
+++ b/include/VBox/ostypes.h
@@ -69,6 +69,8 @@ typedef enum VBOXOSTYPE
     VBOXOSTYPE_Win2k12_x64      = 0x39100,
     VBOXOSTYPE_Win81            = 0x3A000,
     VBOXOSTYPE_Win81_x64        = 0x3A100,
+    VBOXOSTYPE_Win10            = 0x3B000,
+    VBOXOSTYPE_Win10_x64        = 0x3B100,
     VBOXOSTYPE_OS2              = 0x40000,
     VBOXOSTYPE_OS2Warp3         = 0x41000,
     VBOXOSTYPE_OS2Warp4         = 0x42000,
diff --git a/include/VBox/vd-ifs.h b/include/VBox/vd-ifs.h
index 80cdf54..6d80e92 100644
--- a/include/VBox/vd-ifs.h
+++ b/include/VBox/vd-ifs.h
@@ -973,7 +973,10 @@ DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf,
             if (RT_SUCCESS(rc))
             {
                 *ppvData = pbData;
+                /* Exclude terminator if the byte data was obtained using the string query callback. */
                 *pcbData = cb;
+                if (!pCfgIf->pfnQueryBytes)
+                    (*pcbData)--;
             }
             else
                 RTMemFree(pbData);
@@ -984,137 +987,6 @@ DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf,
     return rc;
 }
 
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
- * character value - the memory is locked to prevent paging to disk,
- * useful for memory which holds keys, passwords, etc.
- *
- * @return  VBox status code.
- * @param   pCfgIf      Pointer to configuration callback table.
- * @param   pszName     Name of an zero terminated character value
- * @param   ppszString  Where to store the string pointer. Not set on failure.
- *                      Free this using RTMemFree().
- */
-DECLINLINE(int) VDCFGQueryStringAllocLocked(PVDINTERFACECONFIG pCfgIf,
-                                            const char *pszName, char **ppszString)
-{
-    size_t cb;
-    int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
-    if (RT_SUCCESS(rc))
-    {
-        char *pszString = (char *)RTMemLockedAlloc(cb);
-        if (pszString)
-        {
-            rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb);
-            if (RT_SUCCESS(rc))
-                *ppszString = pszString;
-            else
-                RTMemFree(pszString);
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-    return rc;
-}
-
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) zero terminated
- * character value with default - the memory is locked to prevent paging to disk,
- * useful for memory which holds keys, passwords, etc.
- *
- * @return  VBox status code.
- * @param   pCfgIf      Pointer to configuration callback table.
- * @param   pszName     Name of an zero terminated character value
- * @param   ppszString  Where to store the string pointer. Not set on failure.
- *                      Free this using RTMemFree().
- * @param   pszDef      The default value.
- */
-DECLINLINE(int) VDCFGQueryStringAllocLockedDef(PVDINTERFACECONFIG pCfgIf,
-                                               const char *pszName,
-                                               char **ppszString,
-                                               const char *pszDef)
-{
-    size_t cb;
-    int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
-    if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
-    {
-        cb = strlen(pszDef) + 1;
-        rc = VINF_SUCCESS;
-    }
-    if (RT_SUCCESS(rc))
-    {
-        char *pszString = (char *)RTMemLockedAlloc(cb);
-        if (pszString)
-        {
-            rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb);
-            if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
-            {
-                memcpy(pszString, pszDef, cb);
-                rc = VINF_SUCCESS;
-            }
-            if (RT_SUCCESS(rc))
-                *ppszString = pszString;
-            else
-                RTMemFree(pszString);
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-    return rc;
-}
-
-/**
- * Query configuration, dynamically allocated (RTMemAlloc) byte string value -
- * the memory is locked to prevent paging to disk, useful for memory which holds
- * keys, passwords, etc..
- *
- * @return  VBox status code.
- * @param   pCfgIf      Pointer to configuration callback table.
- * @param   pszName     Name of an zero terminated character value
- * @param   ppvData     Where to store the byte string pointer. Not set on failure.
- *                      Free this using RTMemFree().
- * @param   pcbData     Where to store the byte string length.
- */
-DECLINLINE(int) VDCFGQueryBytesAllocLocked(PVDINTERFACECONFIG pCfgIf,
-                                           const char *pszName, void **ppvData, size_t *pcbData)
-{
-    size_t cb;
-    int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb);
-    if (RT_SUCCESS(rc))
-    {
-        char *pbData;
-        Assert(cb);
-
-        pbData = (char *)RTMemLockedAlloc(cb);
-        if (pbData)
-        {
-            if(pCfgIf->pfnQueryBytes)
-                rc = pCfgIf->pfnQueryBytes(pCfgIf->Core.pvUser, pszName, pbData, cb);
-            else
-                rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pbData, cb);
-
-            if (RT_SUCCESS(rc))
-            {
-                *ppvData = pbData;
-                *pcbData = cb;
-            }
-            else
-                RTMemFree(pbData);
-        }
-        else
-            rc = VERR_NO_MEMORY;
-    }
-    return rc;
-}
-
-/**
- * Frees memory allocated using one of the VDCFGQuery*AllocLocked methods.
- */
-DECLINLINE(void) VDCFGMemLockedFree(void *pvData)
-{
-    RTMemLockedFree(pvData);
-}
-
 /** Forward declaration of a VD socket. */
 typedef struct VDSOCKETINT *VDSOCKET;
 /** Pointer to a VD socket. */
diff --git a/include/iprt/asm.h b/include/iprt/asm.h
index f4eb1ba..11c61af 100644
--- a/include/iprt/asm.h
+++ b/include/iprt/asm.h
@@ -2269,7 +2269,7 @@ DECLINLINE(void) ASMAtomicWritePtrVoid(void * volatile *ppv, const void *pv)
 # define ASMAtomicWriteNullPtr(ppv) \
     do \
     { \
-        __typeof__(*(ppv)) volatile * const ppvTypeChecked = (ppv); \
+        __typeof__(*(ppv)) * const ppvTypeChecked = (ppv); \
         AssertCompile(sizeof(*ppv) == sizeof(void *)); \
         Assert(!( (uintptr_t)ppv & ((ARCH_BITS / 8) - 1) )); \
         ASMAtomicWritePtrVoid((void * volatile *)(ppvTypeChecked), NULL); \
diff --git a/include/iprt/asn1.h b/include/iprt/asn1.h
index f5e9b27..987e3a2 100644
--- a/include/iprt/asn1.h
+++ b/include/iprt/asn1.h
@@ -109,6 +109,9 @@ typedef RTASN1ALLOCATORVTABLE const *PCRTASN1ALLOCATORVTABLE;
 /** The default ASN.1 allocator. */
 extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1DefaultAllocator;
 
+/** The Electric Fence ASN.1 allocator. */
+extern RTDATADECL(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator;
+
 
 /**
  * Allocation information.
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
index 8c28a85..4f1b59c 100644
--- a/include/iprt/mangling.h
+++ b/include/iprt/mangling.h
@@ -1017,6 +1017,8 @@
 # define RTPathFilename                                 RT_MANGLER(RTPathFilename)
 # define RTPathFilenameEx                               RT_MANGLER(RTPathFilenameEx)
 # define RTPathGetCurrent                               RT_MANGLER(RTPathGetCurrent)
+# define RTPathGetCurrentDrive                          RT_MANGLER(RTPathGetCurrentDrive)
+# define RTPathGetCurrentOnDrive                        RT_MANGLER(RTPathGetCurrentOnDrive)
 # define RTPathGetMode                                  RT_MANGLER(RTPathGetMode)
 # define RTPathHasExt                                   RT_MANGLER(RTPathHasExt)
 # define RTPathHasPath                                  RT_MANGLER(RTPathHasPath)
@@ -1797,6 +1799,7 @@
 # define RTUriPath                                      RT_MANGLER(RTUriPath)
 # define RTUriQuery                                     RT_MANGLER(RTUriQuery)
 # define RTUriScheme                                    RT_MANGLER(RTUriScheme)
+# define RTUtf16AllocTag                                RT_MANGLER(RTUtf16AllocTag)
 # define RTUtf16CalcLatin1Len                           RT_MANGLER(RTUtf16CalcLatin1Len)
 # define RTUtf16CalcLatin1LenEx                         RT_MANGLER(RTUtf16CalcLatin1LenEx)
 # define RTUtf16CalcUtf8Len                             RT_MANGLER(RTUtf16CalcUtf8Len)
@@ -2913,6 +2916,7 @@
 # define g_RTAsn1Boolean_Vtable                         RT_MANGLER(g_RTAsn1Boolean_Vtable)
 # define g_RTAsn1BitString_Vtable                       RT_MANGLER(g_RTAsn1BitString_Vtable)
 # define g_RTAsn1DefaultAllocator                       RT_MANGLER(g_RTAsn1DefaultAllocator)
+# define g_RTAsn1EFenceAllocator                        RT_MANGLER(g_RTAsn1EFenceAllocator)
 #if 0 /* Disabled for now as I'm not sure the assmbler supports mangling yet. */
 # define g_abRTZeroPage                                 RT_MANGLER(g_abRTZeroPage)
 # define g_abRTZero4K                                   RT_MANGLER(g_abRTZero4K)
diff --git a/include/iprt/nt/nt.h b/include/iprt/nt/nt.h
index 4c16a55..2051214 100644
--- a/include/iprt/nt/nt.h
+++ b/include/iprt/nt/nt.h
@@ -237,6 +237,31 @@ RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULO
                             ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
 RTDECL(int) RTNtPathClose(HANDLE hHandle);
 
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              RTNtPathFree.
+ * @param   phRootDir           Where to return the root handle, if applicable.
+ * @param   pwszPath            The UTF-16 windows-style path.
+ * @param   cwcPath             The max length of the windows-style path in
+ *                              RTUTF16 units.  Use RTSTR_MAX if unknown and @a
+ *                              pwszPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszPath, size_t cwcPath);
+
+/**
+ * Frees the native path and root handle.
+ *
+ * @param   pNtName             The NT path after a successful
+ *                              RTNtPathFromWinUtf16Ex call.
+ * @param   phRootDir           The root handle variable after a successfull
+ *                              RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir);
+
+
 RT_C_DECLS_END
 /** @} */
 
@@ -365,6 +390,178 @@ typedef struct _CLIENT_ID
 typedef CLIENT_ID *PCLIENT_ID;
 #endif
 
+/** @name User Shared Data
+ * @{ */
+
+#ifdef IPRT_NT_USE_WINTERNL
+typedef struct _KSYSTEM_TIME
+{
+    ULONG                   LowPart;
+    LONG                    High1Time;
+    LONG                    High2Time;
+} KSYSTEM_TIME;
+typedef KSYSTEM_TIME *PKSYSTEM_TIME;
+
+typedef enum _NT_PRODUCT_TYPE
+{
+    NtProductWinNt = 1,
+    NtProductLanManNt,
+    NtProductServer
+} NT_PRODUCT_TYPE;
+
+#define PROCESSOR_FEATURE_MAX       64
+
+typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
+{
+    StandardDesign = 0,
+    NEC98x86,
+    EndAlternatives
+} ALTERNATIVE_ARCHITECTURE_TYPE;
+
+# if 0
+typedef struct _XSTATE_FEATURE
+{
+    ULONG                   Offset;
+    ULONG                   Size;
+} XSTATE_FEATURE;
+typedef XSTATE_FEATURE *PXSTATE_FEATURE;
+
+#define MAXIMUM_XSTATE_FEATURES     64
+
+typedef struct _XSTATE_CONFIGURATION
+{
+    ULONG64                 EnabledFeatures;
+    ULONG                   Size;
+    ULONG                   OptimizedSave  : 1;
+    XSTATE_FEATURE          Features[MAXIMUM_XSTATE_FEATURES];
+} XSTATE_CONFIGURATION;
+typedef XSTATE_CONFIGURATION *PXSTATE_CONFIGURATION;
+# endif
+
+typedef struct _KUSER_SHARED_DATA
+{
+    ULONG                   TickCountLowDeprecated;
+    ULONG                   TickCountMultiplier;
+    KSYSTEM_TIME volatile   InterruptTime;
+    KSYSTEM_TIME volatile   SystemTime;
+    KSYSTEM_TIME volatile   TimeZoneBias;
+    USHORT                  ImageNumberLow;
+    USHORT                  ImageNumberHigh;
+    WCHAR                   NtSystemRoot[260];
+    ULONG                   MaxStackTraceDepth;
+    ULONG                   CryptoExponent;
+    ULONG                   TimeZoneId;
+    ULONG                   LargePageMinimum;
+    ULONG                   AitSamplingValue;
+    ULONG                   AppCompatFlag;
+    ULONGLONG               RNGSeedVersion;
+    ULONG                   GlobalValidationRunlevel;
+    LONG volatile           TimeZoneBiasStamp;
+    ULONG                   Reserved2;
+    NT_PRODUCT_TYPE         NtProductType;
+    BOOLEAN                 ProductTypeIsValid;
+    BOOLEAN                 Reserved0[1];
+    USHORT                  NativeProcessorArchitecture;
+    ULONG                   NtMajorVersion;
+    ULONG                   NtMinorVersion;
+    BOOLEAN                 ProcessorFeatures[PROCESSOR_FEATURE_MAX];
+    ULONG                   Reserved1;
+    ULONG                   Reserved3;
+    ULONG volatile          TimeSlip;
+    ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
+    ULONG                   AltArchitecturePad[1];
+    LARGE_INTEGER           SystemExpirationDate;
+    ULONG                   SuiteMask;
+    BOOLEAN                 KdDebuggerEnabled;
+    union
+    {
+        UCHAR               MitigationPolicies;
+        struct
+        {
+            UCHAR           NXSupportPolicy  : 2;
+            UCHAR           SEHValidationPolicy  : 2;
+            UCHAR           CurDirDevicesSkippedForDlls  : 2;
+            UCHAR           Reserved  : 2;
+        };
+    };
+    UCHAR                   Reserved6[2];
+    ULONG volatile          ActiveConsoleId;
+    ULONG volatile          DismountCount;
+    ULONG                   ComPlusPackage;
+    ULONG                   LastSystemRITEventTickCount;
+    ULONG                   NumberOfPhysicalPages;
+    BOOLEAN                 SafeBootMode;
+    UCHAR                   Reserved12[3];
+    union
+    {
+        ULONG               SharedDataFlags;
+        struct
+        {
+            ULONG           DbgErrorPortPresent  : 1;
+            ULONG           DbgElevationEnabled  : 1;
+            ULONG           DbgVirtEnabled  : 1;
+            ULONG           DbgInstallerDetectEnabled  : 1;
+            ULONG           DbgLkgEnabled  : 1;
+            ULONG           DbgDynProcessorEnabled  : 1;
+            ULONG           DbgConsoleBrokerEnabled  : 1;
+            ULONG           DbgSecureBootEnabled  : 1;
+            ULONG           SpareBits  : 24;
+        };
+    };
+    ULONG                   DataFlagsPad[1];
+    ULONGLONG               TestRetInstruction;
+    LONGLONG                QpcFrequency;
+    ULONGLONG               SystemCallPad[3];
+    union
+    {
+        ULONG64 volatile    TickCountQuad;
+        KSYSTEM_TIME volatile TickCount;
+        struct
+        {
+            ULONG           ReservedTickCountOverlay[3];
+            ULONG           TickCountPad[1];
+        };
+    };
+    ULONG                   Cookie;
+    ULONG                   CookiePad[1];
+    LONGLONG                ConsoleSessionForegroundProcessId;
+    ULONGLONG               TimeUpdateLock;
+    ULONGLONG               BaselineSystemTimeQpc;
+    ULONGLONG               BaselineInterruptTimeQpc;
+    ULONGLONG               QpcSystemTimeIncrement;
+    ULONGLONG               QpcInterruptTimeIncrement;
+    ULONG                   QpcSystemTimeIncrement32;
+    ULONG                   QpcInterruptTimeIncrement32;
+    UCHAR                   QpcSystemTimeIncrementShift;
+    UCHAR                   QpcInterruptTimeIncrementShift;
+    UCHAR                   Reserved8[14];
+    USHORT                  UserModeGlobalLogger[16];
+    ULONG                   ImageFileExecutionOptions;
+    ULONG                   LangGenerationCount;
+    ULONGLONG               Reserved4;
+    ULONGLONG volatile      InterruptTimeBias;
+    ULONGLONG volatile      QpcBias;
+    ULONG volatile          ActiveProcessorCount;
+    UCHAR volatile          ActiveGroupCount;
+    UCHAR                   Reserved9;
+    union
+    {
+        USHORT              QpcData;
+        struct
+        {
+            BOOLEAN volatile QpcBypassEnabled;
+            UCHAR           QpcShift;
+        };
+    };
+    LARGE_INTEGER           TimeZoneBiasEffectiveStart;
+    LARGE_INTEGER           TimeZoneBiasEffectiveEnd;
+    XSTATE_CONFIGURATION    XState;
+} KUSER_SHARED_DATA;
+typedef KUSER_SHARED_DATA *PKUSER_SHARED_DATA;
+#endif /* IPRT_NT_USE_WINTERNL */
+/** @} */
+
+
 /** @name Process And Thread Environment Blocks
  * @{ */
 
@@ -1104,7 +1301,10 @@ typedef PPEB_COMMON PPEB;
 typedef TEB_COMMON  TEB;
 typedef PTEB_COMMON PTEB;
 
-#define NtCurrentPeb()  (((PTEB)NtCurrentTeb())->ProcessEnvironmentBlock)
+#define RTNtCurrentTeb()        ((PTEB)NtCurrentTeb())
+#define RTNtCurrentPeb()        (RTNtCurrentTeb()->ProcessEnvironmentBlock)
+#define NtCurrentPeb()          RTNtCurrentPeb()
+#define RTNtCurrentThreadId()   ((uint32_t)(uintptr_t)RTNtCurrentTeb()->ClientId.UniqueThread)
 
 /** @} */
 
@@ -1172,6 +1372,15 @@ typedef struct _FILE_BOTH_DIR_INFORMATION
     WCHAR           FileName[1];
 } FILE_BOTH_DIR_INFORMATION;
 typedef FILE_BOTH_DIR_INFORMATION *PFILE_BOTH_DIR_INFORMATION;
+typedef struct _FILE_BASIC_INFORMATION
+{
+    LARGE_INTEGER   CreationTime;
+    LARGE_INTEGER   LastAccessTime;
+    LARGE_INTEGER   LastWriteTime;
+    LARGE_INTEGER   ChangeTime;
+    ULONG           FileAttributes;
+} FILE_BASIC_INFORMATION;
+typedef FILE_BASIC_INFORMATION *PFILE_BASIC_INFORMATION;
 typedef struct _FILE_STANDARD_INFORMATION
 {
     LARGE_INTEGER   AllocationSize;
@@ -1481,6 +1690,16 @@ typedef enum _SECTION_INFORMATION_CLASS
 } SECTION_INFORMATION_CLASS;
 NTSYSAPI NTSTATUS NTAPI NtQuerySection(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
 
+NTSYSAPI NTSTATUS NTAPI NtCreateSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING pTarget);
+NTSYSAPI NTSTATUS NTAPI NtOpenSymbolicLinkObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+NTSYSAPI NTSTATUS NTAPI NtQuerySymbolicLinkObject(HANDLE, PUNICODE_STRING, PULONG);
+#ifndef SYMBOLIC_LINK_QUERY
+# define SYMBOLIC_LINK_QUERY        UINT32_C(0x00000001)
+#endif
+#ifndef SYMBOLIC_LINK_ALL_ACCESS
+# define SYMBOLIC_LINK_ALL_ACCESS   (STANDARD_RIGHTS_REQUIRED | SYMBOLIC_LINK_QUERY)
+#endif
+
 NTSYSAPI NTSTATUS NTAPI NtQueryInformationThread(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
 NTSYSAPI NTSTATUS NTAPI NtResumeThread(HANDLE, PULONG);
 NTSYSAPI NTSTATUS NTAPI NtSuspendThread(HANDLE, PULONG);
@@ -1599,6 +1818,38 @@ typedef enum _SYSTEM_INFORMATION_CLASS
     SystemInformation_Unknown_62,
     SystemInformation_Unknown_63,
     SystemExtendedHandleInformation, /* 64 */
+    SystemInformation_Unknown_65,
+    SystemInformation_Unknown_66,
+    SystemInformation_Unknown_67,
+    SystemInformation_Unknown_68,
+    SystemInformation_HotPatchInfo, /* 69 */
+    SystemInformation_Unknown_70,
+    SystemInformation_Unknown_71,
+    SystemInformation_Unknown_72,
+    SystemInformation_Unknown_73,
+    SystemInformation_Unknown_74,
+    SystemInformation_Unknown_75,
+    SystemInformation_Unknown_76,
+    SystemInformation_Unknown_77,
+    SystemInformation_Unknown_78,
+    SystemInformation_Unknown_79,
+    SystemInformation_Unknown_80,
+    SystemInformation_Unknown_81,
+    SystemInformation_Unknown_82,
+    SystemInformation_Unknown_83,
+    SystemInformation_Unknown_84,
+    SystemInformation_Unknown_85,
+    SystemInformation_Unknown_86,
+    SystemInformation_Unknown_87,
+    SystemInformation_Unknown_88,
+    SystemInformation_Unknown_89,
+    SystemInformation_Unknown_90,
+    SystemInformation_Unknown_91,
+    SystemInformation_Unknown_92,
+    SystemInformation_Unknown_93,
+    SystemInformation_Unknown_94,
+    SystemInformation_Unknown_95,
+    SystemInformation_KiOpPrefetchPatchCount,
 
     /** @todo fill gap. they've added a whole bunch of things  */
     SystemPolicyInformation = 134,
@@ -1722,11 +1973,40 @@ NTSYSAPI NTSTATUS NTAPI NtYieldExecution(void);
 #ifndef IPRT_NT_USE_WINTERNL
 NTSYSAPI NTSTATUS NTAPI NtWaitForSingleObject(HANDLE, BOOLEAN PLARGE_INTEGER);
 #endif
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTWAITFORSINGLEOBJECT)(HANDLE, BOOLEAN, PLARGE_INTEGER);
 typedef enum _OBJECT_WAIT_TYPE { WaitAllObjects = 0, WaitAnyObject = 1, ObjectWaitTypeHack = 0x7fffffff } OBJECT_WAIT_TYPE;
 NTSYSAPI NTSTATUS NTAPI NtWaitForMultipleObjects(ULONG, PHANDLE, OBJECT_WAIT_TYPE, BOOLEAN, PLARGE_INTEGER);
 
 NTSYSAPI NTSTATUS NTAPI NtQuerySecurityObject(HANDLE, ULONG, PSECURITY_DESCRIPTOR, ULONG, PULONG);
 
+#ifdef IPRT_NT_USE_WINTERNL
+typedef enum _EVENT_TYPE
+{
+    /* Manual reset event. */
+    NotificationEvent = 0,
+    /* Automaitc reset event. */
+    SynchronizationEvent
+} EVENT_TYPE;
+#endif
+NTSYSAPI NTSTATUS NTAPI NtCreateEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
+NTSYSAPI NTSTATUS NTAPI NtOpenEvent(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTCLEAREVENT)(HANDLE);
+NTSYSAPI NTSTATUS NTAPI NtClearEvent(HANDLE);
+NTSYSAPI NTSTATUS NTAPI NtResetEvent(HANDLE, PULONG);
+NTSYSAPI NTSTATUS NTAPI NtSetEvent(HANDLE, PULONG);
+typedef NTSYSAPI NTSTATUS (NTAPI *PFNNTSETEVENT)(HANDLE, PULONG);
+typedef enum _EVENT_INFORMATION_CLASS
+{
+    EventBasicInformation = 0
+} EVENT_INFORMATION_CLASS;
+/** Data returned by NtQueryEvent + EventBasicInformation. */
+typedef struct EVENT_BASIC_INFORMATION
+{
+    EVENT_TYPE  EventType;
+    ULONG       EventState;
+} EVENT_BASIC_INFORMATION;
+typedef EVENT_BASIC_INFORMATION *PEVENT_BASIC_INFORMATION;
+NTSYSAPI NTSTATUS NTAPI NtQueryEvent(HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
 
 #ifdef IPRT_NT_USE_WINTERNL
 /** For NtQueryValueKey. */
@@ -1879,8 +2159,41 @@ typedef struct CSR_MSG_DATA_CREATED_PROCESS
 #define CSR_MSG_NO_CREATED_THREAD     UINT32_C(0x10001)
 NTSYSAPI NTSTATUS NTAPI CsrClientCallServer(PVOID, PVOID, ULONG, SIZE_T);
 #endif
+
 NTSYSAPI VOID NTAPI     LdrInitializeThunk(PVOID, PVOID, PVOID);
+
+typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA
+{
+    ULONG               Flags;
+    PCUNICODE_STRING    FullDllName;
+    PCUNICODE_STRING    BaseDllName;
+    PVOID               DllBase;
+    ULONG               SizeOfImage;
+} LDR_DLL_LOADED_NOTIFICATION_DATA, LDR_DLL_UNLOADED_NOTIFICATION_DATA;
+typedef LDR_DLL_LOADED_NOTIFICATION_DATA *PLDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
+typedef LDR_DLL_LOADED_NOTIFICATION_DATA const *PCLDR_DLL_LOADED_NOTIFICATION_DATA, *PCLDR_DLL_UNLOADED_NOTIFICATION_DATA;
+
+typedef union _LDR_DLL_NOTIFICATION_DATA
+{
+    LDR_DLL_LOADED_NOTIFICATION_DATA    Loaded;
+    LDR_DLL_UNLOADED_NOTIFICATION_DATA  Unloaded;
+} LDR_DLL_NOTIFICATION_DATA;
+typedef LDR_DLL_NOTIFICATION_DATA *PLDR_DLL_NOTIFICATION_DATA;
+typedef LDR_DLL_NOTIFICATION_DATA const *PCLDR_DLL_NOTIFICATION_DATA;
+
+typedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser);
+
+#define LDR_DLL_NOTIFICATION_REASON_LOADED      UINT32_C(1)
+#define LDR_DLL_NOTIFICATION_REASON_UNLOADED    UINT32_C(2)
+NTSYSAPI NTSTATUS NTAPI LdrRegisterDllNotification(ULONG fFlags, PLDR_DLL_NOTIFICATION_FUNCTION pfnCallback, PVOID pvUser,
+                                                   PVOID *pvCookie);
+typedef NTSTATUS (NTAPI *PFNLDRREGISTERDLLNOTIFICATION)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, PVOID, PVOID *);
+NTSYSAPI NTSTATUS NTAPI LdrUnregisterDllNotification(PVOID pvCookie);
+typedef NTSTATUS (NTAPI *PFNLDRUNREGISTERDLLNOTIFICATION)(PVOID);
+
 NTSYSAPI NTSTATUS NTAPI RtlExpandEnvironmentStrings_U(PVOID, PUNICODE_STRING, PUNICODE_STRING, PULONG);
+NTSYSAPI VOID NTAPI     RtlExitUserProcess(NTSTATUS rcExitCode); /**< Vista and later. */
+NTSYSAPI VOID NTAPI     RtlExitUserThread(NTSTATUS rcExitCode);
 NTSYSAPI NTSTATUS NTAPI RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags,
                                                                  IN PCUNICODE_STRING pOrgName,
                                                                  IN PUNICODE_STRING pDefaultSuffix,
@@ -1890,7 +2203,90 @@ NTSYSAPI NTSTATUS NTAPI RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG fFlags
                                                                  IN PULONG pfNewFlags OPTIONAL,
                                                                  IN PSIZE_T pcbFilename OPTIONAL,
                                                                  IN PSIZE_T pcbNeeded OPTIONAL);
+
+# ifdef IPRT_NT_USE_WINTERNL
+typedef NTSTATUS NTAPI RTL_HEAP_COMMIT_ROUTINE(PVOID, PVOID *, PSIZE_T);
+typedef RTL_HEAP_COMMIT_ROUTINE *PRTL_HEAP_COMMIT_ROUTINE;
+typedef struct _RTL_HEAP_PARAMETERS
+{
+    ULONG   Length;
+    SIZE_T  SegmentReserve;
+    SIZE_T  SegmentCommit;
+    SIZE_T  DeCommitFreeBlockThreshold;
+    SIZE_T  DeCommitTotalFreeThreshold;
+    SIZE_T  MaximumAllocationSize;
+    SIZE_T  VirtualMemoryThreshold;
+    SIZE_T  InitialCommit;
+    SIZE_T  InitialReserve;
+    PRTL_HEAP_COMMIT_ROUTINE  CommitRoutine;
+    SIZE_T  Reserved[2];
+} RTL_HEAP_PARAMETERS;
+typedef RTL_HEAP_PARAMETERS *PRTL_HEAP_PARAMETERS;
+NTSYSAPI PVOID NTAPI RtlCreateHeap(ULONG fFlags, PVOID pvHeapBase, SIZE_T cbReserve, SIZE_T cbCommit, PVOID pvLock,
+                                   PRTL_HEAP_PARAMETERS pParameters);
+/** @name Heap flags (for RtlCreateHeap).
+ * @{ */
+/*#  define HEAP_NO_SERIALIZE             UINT32_C(0x00000001)
+#  define HEAP_GROWABLE                 UINT32_C(0x00000002)
+#  define HEAP_GENERATE_EXCEPTIONS      UINT32_C(0x00000004)
+#  define HEAP_ZERO_MEMORY              UINT32_C(0x00000008)
+#  define HEAP_REALLOC_IN_PLACE_ONLY    UINT32_C(0x00000010)
+#  define HEAP_TAIL_CHECKING_ENABLED    UINT32_C(0x00000020)
+#  define HEAP_FREE_CHECKING_ENABLED    UINT32_C(0x00000040)
+#  define HEAP_DISABLE_COALESCE_ON_FREE UINT32_C(0x00000080)*/
+#  define HEAP_SETTABLE_USER_VALUE      UINT32_C(0x00000100)
+#  define HEAP_SETTABLE_USER_FLAG1      UINT32_C(0x00000200)
+#  define HEAP_SETTABLE_USER_FLAG2      UINT32_C(0x00000400)
+#  define HEAP_SETTABLE_USER_FLAG3      UINT32_C(0x00000800)
+#  define HEAP_SETTABLE_USER_FLAGS      UINT32_C(0x00000e00)
+#  define HEAP_CLASS_0                  UINT32_C(0x00000000)
+#  define HEAP_CLASS_1                  UINT32_C(0x00001000)
+#  define HEAP_CLASS_2                  UINT32_C(0x00002000)
+#  define HEAP_CLASS_3                  UINT32_C(0x00003000)
+#  define HEAP_CLASS_4                  UINT32_C(0x00004000)
+#  define HEAP_CLASS_5                  UINT32_C(0x00005000)
+#  define HEAP_CLASS_6                  UINT32_C(0x00006000)
+#  define HEAP_CLASS_7                  UINT32_C(0x00007000)
+#  define HEAP_CLASS_8                  UINT32_C(0x00008000)
+#  define HEAP_CLASS_MASK               UINT32_C(0x0000f000)
+# endif
+# define HEAP_CLASS_PROCESS             HEAP_CLASS_0
+# define HEAP_CLASS_PRIVATE             HEAP_CLASS_1
+# define HEAP_CLASS_KERNEL              HEAP_CLASS_2
+# define HEAP_CLASS_GDI                 HEAP_CLASS_3
+# define HEAP_CLASS_USER                HEAP_CLASS_4
+# define HEAP_CLASS_CONSOLE             HEAP_CLASS_5
+# define HEAP_CLASS_USER_DESKTOP        HEAP_CLASS_6
+# define HEAP_CLASS_CSRSS_SHARED        HEAP_CLASS_7
+# define HEAP_CLASS_CSRSS_PORT          HEAP_CLASS_8
+# ifdef IPRT_NT_USE_WINTERNL
+/*#  define HEAP_CREATE_ALIGN_16          UINT32_C(0x00010000)
+#  define HEAP_CREATE_ENABLE_TRACING    UINT32_C(0x00020000)
+#  define HEAP_CREATE_ENABLE_EXECUTE    UINT32_C(0x00040000)*/
+#  define HEAP_CREATE_VALID_MASK        UINT32_C(0x0007f0ff)
+# endif /* IPRT_NT_USE_WINTERNL */
+/** @} */
+# ifdef IPRT_NT_USE_WINTERNL
+/** @name Heap tagging constants
+ * @{ */
+#  define HEAP_GLOBAL_TAG               UINT32_C(0x00000800)
+/*#  define HEAP_MAXIMUM_TAG              UINT32_C(0x00000fff)
+#  define HEAP_PSEUDO_TAG_FLAG          UINT32_C(0x00008000)
+#  define HEAP_TAG_SHIFT                18 */
+#  define HEAP_TAG_MASK                 (HEAP_MAXIMUM_TAG << HEAP_TAG_SHIFT)
+/** @}  */
+NTSYSAPI PVOID NTAPI    RtlAllocateHeap(HANDLE hHeap, ULONG fFlags, SIZE_T cb);
+NTSYSAPI PVOID NTAPI    RtlReAllocateHeap(HANDLE hHeap, ULONG fFlags, PVOID pvOld, SIZE_T cbNew);
+NTSYSAPI BOOLEAN NTAPI  RtlFreeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem);
+# endif /* IPRT_NT_USE_WINTERNL */
+NTSYSAPI SIZE_T NTAPI   RtlCompactHeap(HANDLE hHeap, ULONG fFlags);
 NTSYSAPI VOID NTAPI     RtlFreeUnicodeString(PUNICODE_STRING);
+NTSYSAPI SIZE_T NTAPI   RtlSizeHeap(HANDLE hHeap, ULONG fFlags, PVOID pvMem);
+NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus(VOID);
+NTSYSAPI ULONG NTAPI    RtlGetLastWin32Error(VOID);
+NTSYSAPI VOID NTAPI     RtlSetLastWin32Error(ULONG uError);
+NTSYSAPI VOID NTAPI     RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS rcNt);
+NTSYSAPI VOID NTAPI     RtlRestoreLastWin32Error(ULONG uError);
 
 RT_C_DECLS_END
 /** @} */
diff --git a/include/iprt/path.h b/include/iprt/path.h
index 7067a1b..d147d95 100644
--- a/include/iprt/path.h
+++ b/include/iprt/path.h
@@ -239,6 +239,32 @@ RTDECL(int)  RTPathSetCurrent(const char *pszPath);
 RTDECL(int)  RTPathGetCurrent(char *pszPath, size_t cchPath);
 
 /**
+ * Gets the current working directory on the specified drive.
+ *
+ * On systems without drive letters, the root slash will be returned.
+ *
+ * @returns IPRT status code.
+ * @param   chDrive         The drive we're querying the driver letter on.
+ * @param   pszPath         Where to store the working directroy path.
+ * @param   cbPath          The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath);
+
+/**
+ * Gets the current working drive of the process.
+ *
+ * Normally drive letter and colon will be returned, never trailing a root
+ * slash.  If the current directory is on a UNC share, the root of the share
+ * will be returned.  On systems without drive letters, an empty string is
+ * returned for consistency.
+ *
+ * @returns IPRT status code.
+ * @param   pszPath         Where to store the working drive or UNC root.
+ * @param   cbPath          The size of the buffer pszPath points to.
+ */
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath);
+
+/**
  * Get the real path (no symlinks, no . or .. components), must exist.
  *
  * @returns iprt status code.
diff --git a/include/iprt/string.h b/include/iprt/string.h
index 22a4097..60d2346 100644
--- a/include/iprt/string.h
+++ b/include/iprt/string.h
@@ -3219,6 +3219,52 @@ RTDECL(uint32_t)    RTStrHash1ExNV(size_t cPairs, va_list va);
  */
 
 /**
+ * Allocates memory for UTF-16 string storage (default tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string.  The first wide char is
+ *          always set to the string terminator char, the contents of the
+ *          remainder of the memory is undefined.  The string must be freed by
+ *          calling RTUtf16Free.
+ *
+ *          NULL is returned if the allocation failed.  Please translate this to
+ *          VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY.  Also consider
+ *          RTUtf16AllocEx if an IPRT status code is required.
+ *
+ * @param   cb                  How many bytes to allocate, will be rounded up
+ *                              to a multiple of two. If this is zero, we will
+ *                              allocate a terminator wide char anyway.
+ */
+#define RTUtf16Alloc(cb)                    RTUtf16AllocTag((cb), RTSTR_TAG)
+
+/**
+ * Allocates memory for UTF-16 string storage (custom tag).
+ *
+ * You should normally not use this function, except if there is some very
+ * custom string handling you need doing that isn't covered by any of the other
+ * APIs.
+ *
+ * @returns Pointer to the allocated UTF-16 string.  The first wide char is
+ *          always set to the string terminator char, the contents of the
+ *          remainder of the memory is undefined.  The string must be freed by
+ *          calling RTUtf16Free.
+ *
+ *          NULL is returned if the allocation failed.  Please translate this to
+ *          VERR_NO_UTF16_MEMORY and not VERR_NO_MEMORY.  Also consider
+ *          RTUtf16AllocExTag if an IPRT status code is required.
+ *
+ * @param   cb                  How many bytes to allocate, will be rounded up
+ *                              to a multiple of two. If this is zero, we will
+ *                              allocate a terminator wide char anyway.
+ * @param   pszTag              Allocation tag used for statistics and such.
+ */
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag);
+
+
+/**
  * Free a UTF-16 string allocated by RTStrToUtf16(), RTStrToUtf16Ex(),
  * RTLatin1ToUtf16(), RTLatin1ToUtf16Ex(), RTUtf16Dup() or RTUtf16DupEx().
  *
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
index c3ae0ec..5a8a459 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.cpp
@@ -130,6 +130,9 @@ ULONG DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
                 case 3:
                     g_enmVbgdNtVer = VBGDNTVER_WIN81;
                     break;
+                case 4:
+                    g_enmVbgdNtVer = VBGDNTVER_WIN10;
+                    break;
                 default:
                     Log(("VBoxGuest::DriverEntry: Unknown version of Windows (%u.%u), refusing!\n", ulMajorVer, ulMinorVer));
                     rc = STATUS_DRIVER_UNABLE_TO_LOAD;
@@ -1304,6 +1307,14 @@ VBOXOSTYPE vbgdNtVersionToOSType(VBGDNTVER enmNtVer)
 #endif
             break;
 
+        case VBGDNTVER_WIN10:
+#if ARCH_BITS == 64
+            enmOsType = VBOXOSTYPE_Win10_x64;
+#else
+            enmOsType = VBOXOSTYPE_Win10;
+#endif
+            break;
+
         default:
             /* We don't know, therefore NT family. */
             enmOsType = VBOXOSTYPE_WinNT;
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
index aee6367..8491a20 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win.h
@@ -136,6 +136,7 @@ typedef enum VBGDNTVER
     VBGDNTVER_WIN7,
     VBGDNTVER_WIN8,
     VBGDNTVER_WIN81,
+    VBGDNTVER_WIN10
 } VBGDNTVER;
 extern VBGDNTVER g_enmVbgdNtVer;
 
diff --git a/src/VBox/Additions/linux/Makefile.kmk b/src/VBox/Additions/linux/Makefile.kmk
index 4ac2c75..26f2da7 100644
--- a/src/VBox/Additions/linux/Makefile.kmk
+++ b/src/VBox/Additions/linux/Makefile.kmk
@@ -252,7 +252,7 @@ $(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),\
 
 # pattern rule for stripping and copying vbox-greeter to the installation directory
 $(addprefix $(VBOX_LNX_ADD_INST_SBIN_DIR),vbox-greeter): \
-		$(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(subst linux,linux2,$(PATH_STAGE_BIN))/additions/% \
+		$(VBOX_LNX_ADD_INST_SBIN_DIR)% : $(subst linux.amd64/release,linux.amd64/release/greeter,$(subst linux.x86/release,linux.x86/release/greeter,$(PATH_STAGE_BIN)))/additions/% \
 		| $$(dir $$@)
 	$(call MSG_INST_FILE,$<,$@)
 	$(QUIET)$(INSTALL) -m 0755 $< $@
diff --git a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
index 726e207..d6dab14 100644
--- a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
+++ b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
@@ -537,11 +537,8 @@ vbox_output_set_property(xf86OutputPtr output, Atom property,
             return FALSE;
         pVBox->aPreferredSize[cDisplay].cx = w;
         pVBox->aPreferredSize[cDisplay].cy = h;
-        return TRUE;
     }
-    if (property == vboxAtomEDID())
-        return TRUE;
-    return FALSE;
+    return TRUE;
 }
 #endif
 
diff --git a/src/VBox/Debugger/DBGPlugInSolaris.cpp b/src/VBox/Debugger/DBGPlugInSolaris.cpp
index 4c7f017..c8fa67f 100644
--- a/src/VBox/Debugger/DBGPlugInSolaris.cpp
+++ b/src/VBox/Debugger/DBGPlugInSolaris.cpp
@@ -516,7 +516,7 @@ static void dbgDiggerSolarisProcessModCtl32(PUVM pUVM, PDBGDIGGERSOLARIS pThis,
         return;
 
     /* Ignore modules without symbols. */
-    if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symspace)
+    if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symsize)
         return;
 
     /* Check that the symtbl and strings points inside the symspace. */
@@ -662,7 +662,7 @@ static void dbgDiggerSolarisProcessModCtl64(PUVM pUVM, PDBGDIGGERSOLARIS pThis,
         return;
 
     /* Ignore modules without symbols. */
-    if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symspace)
+    if (!Module.symtbl || !Module.strings || !Module.symspace || !Module.symsize)
         return;
 
     /* Check that the symtbl and strings points inside the symspace. */
diff --git a/src/VBox/Devices/Bus/DevPCI.cpp b/src/VBox/Devices/Bus/DevPCI.cpp
index c454d8b..5b16ec1 100644
--- a/src/VBox/Devices/Bus/DevPCI.cpp
+++ b/src/VBox/Devices/Bus/DevPCI.cpp
@@ -804,7 +804,6 @@ static void pciR3Piix3Reset(PIIX3State *d)
     pci_conf[0x80] = 0x00;
     pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
     pci_conf[0xa0] = 0x08;
-    pci_conf[0xa0] = 0x08;
     pci_conf[0xa2] = 0x00;
     pci_conf[0xa3] = 0x00;
     pci_conf[0xa4] = 0x00;
diff --git a/src/VBox/Devices/EFI/DevSmc.cpp b/src/VBox/Devices/EFI/DevSmc.cpp
index fc7cf37..1de17a4 100644
--- a/src/VBox/Devices/EFI/DevSmc.cpp
+++ b/src/VBox/Devices/EFI/DevSmc.cpp
@@ -243,6 +243,7 @@ AssertCompileMembersAtSameOffset(DEVSMC, u.abRegsRW[SMC_REG_STATUS_CODE], DEVSMC
 /** Pointer to the SMC state. */
 typedef DEVSMC *PDEVSMC;
 
+#ifndef VBOX_DEVICE_STRUCT_TESTCASE
 
 
 /**
@@ -1428,3 +1429,4 @@ const PDMDEVREG g_DeviceSmc =
 };
 
 #endif /* IN_RING3 */
+#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd
index e726413..de413bd 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd differ
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd
index d22e9ce..043d1d8 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd differ
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
index 28ab4a8..ca12aab 100644
--- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
@@ -522,6 +522,9 @@ static int vbvaEnable (unsigned uScreenId, PVGASTATE pVGAState, VBVACONTEXT *pCt
 
         pCtx->aViews[uScreenId].pVBVA = pVBVA;
         pCtx->aViews[uScreenId].u32VBVAOffset = u32Offset;
+
+        /* VBVA is working so disable the pause. */
+        pCtx->fPaused = false;
     }
 
     return rc;
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index 9bfbffa..1d033db 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -18,9 +18,6 @@
 SUB_DEPTH = ../../..
 include $(KBUILD_PATH)/subheader.kmk
 
-# Enable the new SMC code.
-VBOX_WITH_SMC_NEW = 1
-
 # Make sure our Config.kmk is included.
 ifndef VBOX_DEVICES_CONFIG_KMK_INCLUDED
  include $(PATH_SUB_CURRENT)/Config.kmk
@@ -121,8 +118,7 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	VBOX_WITH_HGCM \
  	$(if $(VBOX_BIOS_DMI_FALLBACK),VBOX_BIOS_DMI_FALLBACK,) \
  	VBOX_WITH_DMI_CHASSIS \
- 	VBOX_WITH_DMI_OEMSTRINGS \
-	$(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ 	VBOX_WITH_DMI_OEMSTRINGS
  VBoxDD_DEFS.win         = _WIN32_WINNT=0x0510
  ifeq ($(KBUILD_TARGET_ARCH),x86)
   VBoxDD_DEFS.darwin     = VBOX_WITH_2X_4GB_ADDR_SPACE
@@ -139,7 +135,7 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	Bus/DevPciIch9.cpp \
  	Bus/MsiCommon.cpp \
  	Bus/MsixCommon.cpp \
-	$(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+	EFI/DevSmc.cpp \
  	Graphics/DevVGA.cpp \
  	Storage/DevATA.cpp \
  	PC/DevPit-i8254.cpp \
@@ -802,7 +798,7 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	Bus/DevPciIch9.cpp \
  	Bus/MsiCommon.cpp \
  	Bus/MsixCommon.cpp \
-	$(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+	EFI/DevSmc.cpp \
   	Graphics/DevVGA.cpp \
   	Input/DevPS2.cpp \
  	Input/PS2K.cpp \
@@ -912,7 +908,7 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  # VBoxDD2 (shared object)
  #
  VBoxDD2_TEMPLATE        = VBoxR3DllWarnNoPic
- VBoxDD2_DEFS            = IN_VBOXDD2 $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ VBoxDD2_DEFS            = IN_VBOXDD2
  VBoxDD2_INCS           := \
 	build \
  	$(PATH_SUB_CURRENT)
@@ -920,7 +916,6 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	build/VBoxDD2.cpp  \
  	PC/DevAPIC.cpp \
  	PC/DevIoApic.cpp \
- 	$(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp) \
  	PC/DevLPC.cpp
  VBoxDD2_LIBS            = \
  	$(PATH_STAGE_LIB)/PcBiosBin$(VBOX_SUFF_LIB) \
@@ -956,7 +951,7 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  	Bus/DevPciIch9.cpp \
  	Bus/MsiCommon.cpp \
  	Bus/MsixCommon.cpp \
-	$(if $(VBOX_WITH_SMC_NEW),EFI/DevSmc.cpp,) \
+	EFI/DevSmc.cpp \
  	Graphics/DevVGA.cpp \
  	Input/DevPS2.cpp \
  	Input/PS2K.cpp \
@@ -1085,12 +1080,10 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
   # VBoxDD2GC (LGPL sysmod)
   #
   VBoxDD2GC_TEMPLATE       = VBoxRc
-  VBoxDD2GC_DEFS           = $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
   VBoxDD2GC_INCS           = build
   VBoxDD2GC_SOURCES        = \
   	PC/DevAPIC.cpp \
-  	PC/DevIoApic.cpp \
-  	$(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp)
+  	PC/DevIoApic.cpp
   if1of ($(VBOX_LDR_FMT32), pe lx)
    VBoxDD2GC_LIBS          = \
    	$(PATH_STAGE_LIB)/VMMRCBuiltin$(VBOX_SUFF_LIB) \
@@ -1103,13 +1096,12 @@ if !defined(VBOX_ONLY_EXTPACKS)         # Goes on almost to the end of the file.
  # VBoxDD2R0 (LGPL sysmod)
  #
  VBoxDD2R0_TEMPLATE       = VBoxR0
- VBoxDD2R0_DEFS           = IN_RT_R0 $(if $(VBOX_WITH_SMC_NEW),VBOX_WITH_SMC_NEW,)
+ VBoxDD2R0_DEFS           = IN_RT_R0
  VBoxDD2R0_INCS           = build
  VBoxDD2R0_SOURCES        = \
  	build/VBoxDD2R0.cpp \
  	PC/DevAPIC.cpp \
  	PC/DevIoApic.cpp \
- 	$(if $(VBOX_WITH_SMC_NEW),,PC/DevSMC.cpp)
 
  if1of ($(VBOX_LDR_FMT), pe lx)
   VBoxDD2R0_LIBS          = \
diff --git a/src/VBox/Devices/Network/DrvNAT.cpp b/src/VBox/Devices/Network/DrvNAT.cpp
index 12dbb94..0980633 100644
--- a/src/VBox/Devices/Network/DrvNAT.cpp
+++ b/src/VBox/Devices/Network/DrvNAT.cpp
@@ -971,7 +971,7 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
 {
     PDRVNAT pThis = (PDRVNAT)pvUser;
 
-    LogRel(("NAT: System configuration has changed\n"));
+    Log2(("NAT: System configuration has changed\n"));
 
     /* Check if any of parameters we are interested in were actually changed. If the size
      * of hChangedKeys is 0, it means that SCDynamicStore has been restarted. */
@@ -983,14 +983,13 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
         if (CFArrayContainsValue(hChangedKeys, CFRangeMake(0, CFArrayGetCount(hChangedKeys)), pDNSKey))
         {
             LogRel(("NAT: DNS servers changed, triggering reconnect\n"));
-
+#if 0
             CFDictionaryRef hDnsDict = (CFDictionaryRef)SCDynamicStoreCopyValue(hDynStor, pDNSKey);
             if (hDnsDict)
             {
                 CFArrayRef hArrAddresses = (CFArrayRef)CFDictionaryGetValue(hDnsDict, kSCPropNetDNSServerAddresses);
                 if (hArrAddresses && CFArrayGetCount(hArrAddresses) > 0)
                 {
-#if 1
                     /* Dump DNS servers list. */
                     for (int i = 0; i < CFArrayGetCount(hArrAddresses); i++)
                     {
@@ -998,7 +997,6 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
                         const char *pszDNSAddr  =  pDNSAddrStr ? CFStringGetCStringPtr(pDNSAddrStr, CFStringGetSystemEncoding()) : NULL;
                         LogRel(("NAT: New DNS server#%d: %s\n", i, pszDNSAddr ? pszDNSAddr : "None"));
                     }
-#endif
                 }
                 else
                     LogRel(("NAT: DNS server list is empty (1)\n"));
@@ -1007,14 +1005,14 @@ static DECLCALLBACK(void) drvNatDnsChanged(SCDynamicStoreRef hDynStor, CFArrayRe
             }
             else
                 LogRel(("NAT: DNS server list is empty (2)\n"));
-
+#endif
             drvNATHostNetworkConfigurationChangeEventStrategySelector(pThis, /* RT_OS_DARWIN */ true);
         }
         else
-            LogRel(("NAT: No DNS changes detected\n"));
+            Log2(("NAT: No DNS changes detected\n"));
     }
     else
-        LogRel(("NAT: SCDynamicStore has been restarted\n"));
+        Log2(("NAT: SCDynamicStore has been restarted\n"));
 }
 #endif
 
diff --git a/src/VBox/Devices/Network/slirp/slirp_dns.c b/src/VBox/Devices/Network/slirp/slirp_dns.c
index 4f56304..9ff44c1 100644
--- a/src/VBox/Devices/Network/slirp/slirp_dns.c
+++ b/src/VBox/Devices/Network/slirp/slirp_dns.c
@@ -247,16 +247,9 @@ static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
         *ppszDomain = NULL;
 
     Log(("NAT: DNS Servers:\n"));
-#ifdef RT_OS_DARWIN
-    LogRel(("NAT: /etc/resolv.conf dump:\n"));
-    int cLine = 0;
-#endif
     while (    RT_SUCCESS(rc = RTFileGets(ResolvConfFile, buff, sizeof(buff), &bytes))
             && rc != VERR_EOF)
     {
-#ifdef RT_OS_DARWIN
-        LogRel(("NAT: resolv.conf:%d: %s\n", ++cLine, buff));
-#endif
         struct dns_entry *pDns = NULL;
         if (   cNameserversFound == 4
             && !fWarnTooManyDnsServers
diff --git a/src/VBox/Devices/PC/BIOS/ahci.c b/src/VBox/Devices/PC/BIOS/ahci.c
index d91a8e9..cb1ccf4 100644
--- a/src/VBox/Devices/PC/BIOS/ahci.c
+++ b/src/VBox/Devices/PC/BIOS/ahci.c
@@ -728,7 +728,7 @@ void ahci_port_detect_device(ahci_t __far *ahci, uint8_t u8Port)
                 else
                     set_geom_lba(&lgeo, sectors);   /* Default EDD-style translated LBA geometry. */
 
-                BX_INFO("AHCI %d-P#%d: PCHS=%u/%d/%d LCHS=%u/%u/%u %ld sectors\n", devcount_ahci,
+                BX_INFO("AHCI %d-P#%d: PCHS=%u/%u/%u LCHS=%u/%u/%u %lu sectors\n", devcount_ahci,
                         u8Port, cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt, sectors);
 
                 bios_dsk->devices[hd_index].lchs = lgeo;
diff --git a/src/VBox/Devices/PC/BIOS/ata.c b/src/VBox/Devices/PC/BIOS/ata.c
index 921433d..84a17f7 100644
--- a/src/VBox/Devices/PC/BIOS/ata.c
+++ b/src/VBox/Devices/PC/BIOS/ata.c
@@ -512,8 +512,8 @@ void BIOSCALL ata_detect(void)
             else
                 set_geom_lba(&lgeo, sectors);   /* Default EDD-style translated LBA geometry. */
 
-            BX_INFO("ata%d-%d: PCHS=%u/%d/%d LCHS=%u/%u/%u\n", channel, slave,
-                    cylinders,heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt);
+            BX_INFO("ata%d-%d: PCHS=%u/%u/%u LCHS=%u/%u/%u\n", channel, slave,
+                    cylinders, heads, spt, lgeo.cylinders, lgeo.heads, lgeo.spt);
 
             bios_dsk->devices[device].device         = DSK_DEVICE_HD;
             bios_dsk->devices[device].removable      = removable;
diff --git a/src/VBox/Devices/PC/BIOS/scsi.c b/src/VBox/Devices/PC/BIOS/scsi.c
index b40255e..236a4db 100644
--- a/src/VBox/Devices/PC/BIOS/scsi.c
+++ b/src/VBox/Devices/PC/BIOS/scsi.c
@@ -511,7 +511,7 @@ void scsi_enumerate_attached_devices(uint16_t io_base)
                 else
                     bios_dsk->devices[hd_index].lchs.cylinders = (uint16_t)cylinders;
 
-                BX_INFO("SCSI %d-ID#%d: LCHS=%u/%u/%u %ld sectors\n", devcount_scsi,
+                BX_INFO("SCSI %d-ID#%d: LCHS=%u/%u/%u %lu sectors\n", devcount_scsi,
                         i, (uint16_t)cylinders, heads, sectors_per_track, sectors);
 
                 /* Write PCHS values. */
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index d2a3add..e5fee2b 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -65,7 +65,7 @@
 #define PM_TMR_FREQ     3579545
 /* Default base for PM PIIX4 device */
 #define PM_PORT_BASE    0x4000
-/* Port offsets in PM device */
+/* Port offsets in PM device */    
 enum
 {
     PM1a_EVT_OFFSET                     = 0x00,
@@ -78,6 +78,9 @@ enum
     GPE1_OFFSET                         =   -1    /**<  not supported  */
 };
 
+/* Undef this to enable 24 bit PM timer (mostly for debugging purposes) */
+#define PM_TMR_32BIT
+
 #define BAT_INDEX       0x00004040
 #define BAT_DATA        0x00004044
 #define SYSI_INDEX      0x00004048
@@ -218,6 +221,10 @@ typedef struct ACPIState
     PTMTIMERR0          pPmTimerR0;
     PTMTIMERRC          pPmTimerRC;
 
+    /* PM Timer last calculated value */
+    uint32_t            uPmTimerVal;
+    uint32_t            Alignment0;
+
     uint32_t            gpe0_en;
     uint32_t            gpe0_sts;
 
@@ -309,7 +316,11 @@ typedef struct ACPIState
     /** ACPI port interface. */
     PDMIACPIPORT        IACPIPort;
     /** Pointer to the device instance. */
-    PPDMDEVINSR3        pDevIns;
+    PPDMDEVINSR3        pDevInsR3;
+    PPDMDEVINSR0        pDevInsR0;
+    PPDMDEVINSRC        pDevInsRC;
+
+    uint32_t            Alignment1;
     /** Pointer to the driver base interface. */
     R3PTRTYPE(PPDMIBASE) pDrvBase;
     /** Pointer to the driver connector interface. */
@@ -332,7 +343,7 @@ typedef struct ACPIState
     uint8_t             au8OemTabId[8];
     /** ACPI custom OEM Rev */
     uint32_t            u32OemRevision;
-    uint32_t            Alignment0;
+    uint32_t            Alignment2;
 
     /** The custom table binary data. */
     R3PTRTYPE(uint8_t *) pu8CustBin;
@@ -484,6 +495,17 @@ struct ACPITBLFADT
 #define FADT_FL_FORCE_APIC_CLUSTER_MODEL  RT_BIT(18)
 #define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
 
+/* PM Timer mask and msb */
+#ifndef PM_TMR_32BIT
+#define TMR_VAL_MSB     0x800000
+#define TMR_VAL_MASK    0xffffff
+#undef  FADT_FL_TMR_VAL_EXT
+#define FADT_FL_TMR_VAL_EXT     0
+#else
+#define TMR_VAL_MSB     0x80000000
+#define TMR_VAL_MASK    0xffffffff
+#endif
+
     /** Start of the ACPI 2.0 extension. */
     ACPIGENADDR         ResetReg;               /**< ext addr of reset register */
     uint8_t             u8ResetVal;             /**< ResetReg value to reset the system */
@@ -619,13 +641,11 @@ RT_C_DECLS_END
 static int acpiR3PlantTables(ACPIState *pThis);
 #endif
 
-#ifdef IN_RING3
-
 /* SCI IRQ */
-DECLINLINE(void) acpiR3SetIrq(ACPIState *pThis, int level)
+DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
 {
     if (pThis->pm1a_ctl & SCI_EN)
-        PDMDevHlpPCISetIrq(pThis->pDevIns, 0, level);
+        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, level);
 }
 
 DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
@@ -650,16 +670,17 @@ DECLINLINE(bool) gpe0_level(ACPIState *pThis)
 
 /**
  * Used by acpiR3PM1aStsWrite, acpiR3PM1aEnWrite, acpiR3PmTimer,
- * acpiR3Port_PowerBuffonPress and acpiR3Port_SleepButtonPress to
- * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
+ * acpiR3Port_PowerBuffonPress, acpiR3Port_SleepButtonPress
+ * and acpiPmTmrRead to update the PM1a.STS and PM1a.EN
+ * registers and trigger IRQs.
  *
  * Caller must hold the state lock.
  *
  * @param   pThis       The ACPI instance.
- * @param   sts         The new GPE0.STS value.
- * @param   en          The new GPE0.EN value.
+ * @param   sts         The new PM1a.STS value.
+ * @param   en          The new PM1a.EN value.
  */
-static void apicR3UpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
+static void apicUpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
 {
     Assert(PDMCritSectIsOwner(&pThis->CritSect));
 
@@ -669,15 +690,17 @@ static void apicR3UpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
     int const old_level = pm1a_level(pThis);
     int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
 
-    Log(("apicR3UpdatePm1a() old=%x new=%x\n", old_level, new_level));
+    Log(("apicUpdatePm1a() old=%x new=%x\n", old_level, new_level));
 
     pThis->pm1a_en = en;
     pThis->pm1a_sts = sts;
 
     if (new_level != old_level)
-        acpiR3SetIrq(pThis, new_level);
+        acpiSetIrq(pThis, new_level);
 }
 
+#ifdef IN_RING3
+
 /**
  * Used by acpiR3Gpe0StsWrite, acpiR3Gpe0EnWrite, acpiAttach and acpiDetach to
  * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
@@ -695,14 +718,14 @@ static void apicR3UpdateGpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
     if (pm1a_level(pThis))
         return;
 
-    int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
+    int const old_level = gpe0_level(pThis);
     int const new_level = (en & sts) != 0;
 
     pThis->gpe0_en  = en;
     pThis->gpe0_sts = sts;
 
     if (new_level != old_level)
-        acpiR3SetIrq(pThis, new_level);
+        acpiSetIrq(pThis, new_level);
 }
 
 /**
@@ -713,7 +736,7 @@ static void apicR3UpdateGpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
  */
 static int acpiR3DoPowerOff(ACPIState *pThis)
 {
-    int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
+    int rc = PDMDevHlpVMPowerOff(pThis->pDevInsR3);
     if (RT_FAILURE(rc))
         AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
     return rc;
@@ -734,19 +757,19 @@ static int acpiR3DoSleep(ACPIState *pThis)
     pThis->fSetWakeupOnResume = true;
     if (pThis->fSuspendToSavedState)
     {
-        rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
+        rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevInsR3);
         if (rc != VERR_NOT_SUPPORTED)
             AssertRC(rc);
         else
         {
             LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
-            rc = PDMDevHlpVMSuspend(pThis->pDevIns);
+            rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
             AssertRC(rc);
         }
     }
     else
     {
-        rc = PDMDevHlpVMSuspend(pThis->pDevIns);
+        rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
         AssertRC(rc);
     }
     return rc;
@@ -763,7 +786,7 @@ static DECLCALLBACK(int) acpiR3Port_PowerButtonPress(PPDMIACPIPORT pInterface)
 
     Log(("acpiR3Port_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
     pThis->fPowerButtonHandled = false;
-    apicR3UpdatePm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
+    apicUpdatePm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
 
     DEVACPI_UNLOCK(pThis);
     return VINF_SUCCESS;
@@ -823,7 +846,7 @@ static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
     ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     DEVACPI_LOCK_R3(pThis);
 
-    apicR3UpdatePm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
+    apicUpdatePm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
 
     DEVACPI_UNLOCK(pThis);
     return VINF_SUCCESS;
@@ -841,11 +864,40 @@ static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
 static void acpiR3PmTimerReset(ACPIState *pThis, uint64_t uNow)
 {
     uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
-    uint64_t uInterval  = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
-    TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
+    uint32_t uPmTmrCyclesToRollover = TMR_VAL_MSB - (pThis->uPmTimerVal & (TMR_VAL_MSB - 1));
+    uint64_t uInterval  = ASMMultU64ByU32DivByU32(uPmTmrCyclesToRollover, uTimerFreq, PM_TMR_FREQ);
+    TMTimerSet(pThis->pPmTimerR3, uNow + uInterval + 1);
     Log(("acpi: uInterval = %RU64\n", uInterval));
 }
 
+#endif
+
+/**
+  * Used by acpiR3PMTimer & acpiPmTmrRead to update TMR_VAL and update TMR_STS
+  * 
+  * The caller is expected to either hold the clock lock or to have made sure
+  * the VM is resetting or loading state.
+  *
+  * @param   pThis              The ACPI instance
+  * @param   uNow               The current time
+  */
+
+static void acpiPmTimerUpdate(ACPIState *pThis, uint64_t u64Now)
+{
+    uint32_t msb = pThis->uPmTimerVal & TMR_VAL_MSB;
+    uint64_t u64Elapsed = u64Now - pThis->u64PmTimerInitial;
+    Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPmTimer)));
+
+    pThis->uPmTimerVal = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer))) & TMR_VAL_MASK;
+
+    if ( (pThis->uPmTimerVal & TMR_VAL_MSB) != msb)
+    {
+        apicUpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
+    }
+}
+
+#ifdef IN_RING3
+
 /**
  * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
  */
@@ -859,10 +911,11 @@ static DECLCALLBACK(void) acpiR3PmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, voi
     Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
          pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
          pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
-    apicR3UpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
+    uint64_t u64Now = TMTimerGet(pTimer);
+    acpiPmTimerUpdate(pThis, u64Now);
     DEVACPI_UNLOCK(pThis);
 
-    acpiR3PmTimerReset(pThis, TMTimerGet(pTimer));
+    acpiR3PmTimerReset(pThis, u64Now);
 }
 
 /**
@@ -1342,7 +1395,7 @@ PDMBOTHCBDECL(int) acpiR3PM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT
     Log(("acpiR3PM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
     u32 &= ~(RSR_EN | IGN_EN);
     u32 &= 0xffff;
-    apicR3UpdatePm1a(pThis, pThis->pm1a_sts, u32);
+    apicUpdatePm1a(pThis, pThis->pm1a_sts, u32);
 
     DEVACPI_UNLOCK(pThis);
     return VINF_SUCCESS;
@@ -1385,7 +1438,7 @@ PDMBOTHCBDECL(int) acpiR3PM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT
     if (u32 & PWRBTN_STS)
         pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
     u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
-    apicR3UpdatePm1a(pThis, u32, pThis->pm1a_en);
+    apicUpdatePm1a(pThis, u32, pThis->pm1a_en);
 
     DEVACPI_UNLOCK(pThis);
     return VINF_SUCCESS;
@@ -1489,24 +1542,31 @@ PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port
 
     /*
      * We use the clock lock to serialize access to u64PmTimerInitial and to
-     * make sure we get a reliable time from the clock.
+     * make sure we get a reliable time from the clock
+     * as well as and to prevent uPmTimerVal from being updated during read.
      */
+
     int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
-    if (rc == VINF_SUCCESS)
+    if (rc != VINF_SUCCESS)
+        return rc;
+    
+    rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
+    if (rc != VINF_SUCCESS)
     {
-        uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
-        uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
-        TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
-
-        /*
-         * Calculate the return value.
-         */
-        DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
-        uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
-        *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
-        Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
+            TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
+            return rc;
     }
 
+    uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
+    acpiPmTimerUpdate(pThis, u64Now);
+    *pu32 = pThis->uPmTimerVal;
+
+    DEVACPI_UNLOCK(pThis);
+    TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
+
+    DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
+    Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
+
     NOREF(pvUser); NOREF(Port);
     return rc;
 }
@@ -1711,7 +1771,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
 
 #define R(offset, cnt, writer, reader, description) \
     do { \
-        rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
+        rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
                                       NULL, NULL, description); \
         if (RT_FAILURE(rc)) \
             return rc; \
@@ -1730,7 +1790,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
     /* register RC stuff */
     if (pThis->fGCEnabled)
     {
-        rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
+        rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
                                        1, 0, NULL, "acpiPMTmrRead",
                                        NULL, NULL, "ACPI PM Timer");
         AssertRCReturn(rc, rc);
@@ -1739,7 +1799,7 @@ static int acpiR3RegisterPmHandlers(ACPIState *pThis)
     /* register R0 stuff */
     if (pThis->fR0Enabled)
     {
-        rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
+        rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
                                        1, 0, NULL, "acpiPMTmrRead",
                                        NULL, NULL, "ACPI PM Timer");
         AssertRCReturn(rc, rc);
@@ -1759,7 +1819,7 @@ static int acpiR3UnregisterPmHandlers(ACPIState *pThis)
 {
 #define U(offset, cnt) \
     do { \
-        int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiR3CalcPmPort(pThis, offset), cnt); \
+        int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt); \
         AssertRCReturn(rc, rc); \
     } while (0)
 #define L       (GPE0_BLK_LEN / 2)
@@ -1870,6 +1930,26 @@ static const SSMFIELD g_AcpiSavedStateFields6[] =
     SSMFIELD_ENTRY_TERM()
 };
 
+/**
+ * Saved state structure description, version 7.
+ */
+static const SSMFIELD g_AcpiSavedStateFields7[] =
+{
+    SSMFIELD_ENTRY(ACPIState, pm1a_en),
+    SSMFIELD_ENTRY(ACPIState, pm1a_sts),
+    SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
+    SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
+    SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
+    SSMFIELD_ENTRY(ACPIState, gpe0_en),
+    SSMFIELD_ENTRY(ACPIState, gpe0_sts),
+    SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
+    SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
+    SSMFIELD_ENTRY(ACPIState, uSleepState),
+    SSMFIELD_ENTRY(ACPIState, u8IndexShift),
+    SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
+    SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
+    SSMFIELD_ENTRY_TERM()
+};
 
 /**
  * @callback_method_impl{FNSSMDEVSAVEEXEC}
@@ -1877,7 +1957,7 @@ static const SSMFIELD g_AcpiSavedStateFields6[] =
 static DECLCALLBACK(int) acpiR3SaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
 {
     ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
-    return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
+    return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
 }
 
 /**
@@ -1907,6 +1987,9 @@ static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHand
         case 6:
             rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
             break;
+        case 7:
+            rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
+            break;
         default:
             rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
             break;
@@ -1923,7 +2006,14 @@ static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHand
         if (RT_FAILURE(rc))
             return rc;
         TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
-        acpiR3PmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
+        DEVACPI_LOCK_R3(pThis);
+        uint64_t u64Now = TMTimerGet(pThis->pPmTimerR3);
+        /* The interrupt may be incorrectly re-generated
+         * if the state is restored from versions < 7
+         */
+        acpiPmTimerUpdate(pThis, u64Now);
+        acpiR3PmTimerReset(pThis, u64Now);
+        DEVACPI_UNLOCK(pThis);
         TMTimerUnlock(pThis->pPmTimerR3);
     }
     return rc;
@@ -1995,7 +2085,7 @@ static void acpiR3WriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
  */
 DECLINLINE(void) acpiR3PhysCopy(ACPIState *pThis, RTGCPHYS32 GCPhys32Dst, const void *pvSrc, size_t cbToCopy)
 {
-    PDMDevHlpPhysWrite(pThis->pDevIns, GCPhys32Dst, pvSrc, cbToCopy);
+    PDMDevHlpPhysWrite(pThis->pDevInsR3, GCPhys32Dst, pvSrc, cbToCopy);
 }
 
 /**
@@ -2129,7 +2219,7 @@ static int acpiR3SetupRsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_en
 
     rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
     if (!rsdt)
-        return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
+        return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
 
     acpiR3PrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
     for (unsigned int i = 0; i < nb_entries; ++i)
@@ -2513,15 +2603,15 @@ static int acpiR3PlantTables(ACPIState *pThis)
     cbRsdt += cAddr*sizeof(uint32_t);  /* each entry: 32 bits phys. address. */
     cbXsdt += cAddr*sizeof(uint64_t);  /* each entry: 64 bits phys. address. */
 
-    rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
+    rc = CFGMR3QueryU64(pThis->pDevInsR3->pCfg, "RamSize", &pThis->u64RamSize);
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
                                 N_("Configuration error: Querying \"RamSize\" as integer failed"));
 
     uint32_t cbRamHole;
-    rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
+    rc = CFGMR3QueryU32Def(pThis->pDevInsR3->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
                                 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
 
     /*
@@ -2578,7 +2668,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
 
     void  *pvSsdtCode = NULL;
     size_t cbSsdt = 0;
-    rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdt);
+    rc = acpiPrepareSsdt(pThis->pDevInsR3, &pvSsdtCode, &cbSsdt);
     if (RT_FAILURE(rc))
         return rc;
 
@@ -2589,14 +2679,14 @@ static int acpiR3PlantTables(ACPIState *pThis)
 
     void  *pvDsdtCode = NULL;
     size_t cbDsdt = 0;
-    rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdt);
+    rc = acpiPrepareDsdt(pThis->pDevInsR3, &pvDsdtCode, &cbDsdt);
     if (RT_FAILURE(rc))
         return rc;
 
     GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdt, 16);
 
     if (GCPhysCur > 0x10000)
-        return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
+        return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_TOO_MUCH_DATA,
                                 N_("Error: ACPI tables bigger than 64KB"));
 
     Log(("RSDP 0x%08X\n", apicR3FindRsdpSpace()));
@@ -2617,7 +2707,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
 
     acpiR3SetupRsdp(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
     acpiR3SetupDsdt(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdt);
-    acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
+    acpiCleanupDsdt(pThis->pDevInsR3, pvDsdtCode);
     acpiR3SetupFacs(pThis, GCPhysFacs + addend);
     acpiR3SetupFadt(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
 
@@ -2649,7 +2739,7 @@ static int acpiR3PlantTables(ACPIState *pThis)
     }
 
     acpiR3SetupSsdt(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdt);
-    acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
+    acpiCleanupSsdt(pThis->pDevInsR3, pvSsdtCode);
     aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
     aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
 
@@ -2826,6 +2916,7 @@ static DECLCALLBACK(void) acpiR3Reset(PPDMDEVINS pDevIns)
     pThis->pm1a_sts          = 0;
     pThis->pm1a_ctl          = 0;
     pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
+    pThis->uPmTimerVal       = 0;
     acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
     pThis->uBatteryIndex     = 0;
     pThis->uSystemInfoIndex  = 0;
@@ -2875,7 +2966,9 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
      */
     /** @todo move more of the code up! */
 
-    pThis->pDevIns = pDevIns;
+    pThis->pDevInsR3 = pDevIns;
+    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
+    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     VMCPUSET_EMPTY(&pThis->CpuSetAttached);
     VMCPUSET_EMPTY(&pThis->CpuSetLocked);
     pThis->idCpuLockCheck  = UINT32_C(0xffffffff);
@@ -3106,34 +3199,34 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
     }
 
     char *pszOemId = NULL;
-    rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiOemId", &pszOemId, "VBOX  ");
+    rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiOemId", &pszOemId, "VBOX  ");
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
     size_t cbOemId = strlen(pszOemId);
     if (cbOemId > 6)
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
     memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
     memcpy(pThis->au8OemId, pszOemId, cbOemId);
     MMR3HeapFree(pszOemId);
 
     char *pszCreatorId = NULL;
-    rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
+    rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
     size_t cbCreatorId = strlen(pszCreatorId);
     if (cbCreatorId > 4)
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
     memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
     memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
     MMR3HeapFree(pszCreatorId);
 
-    rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
+    rc = CFGMR3QueryU32Def(pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
     if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
     pThis->u32OemRevision         = RT_H2LE_U32(0x1);
 
@@ -3141,16 +3234,16 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
      * Get the custom table binary file name.
      */
     char *pszCustBinFile;
-    rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "CustomTable", &pszCustBinFile);
+    rc = CFGMR3QueryStringAlloc(pCfg, "CustomTable", &pszCustBinFile);
     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-        rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "SLICTable", &pszCustBinFile);
+        rc = CFGMR3QueryStringAlloc(pCfg, "SLICTable", &pszCustBinFile);
     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
     {
         pszCustBinFile = NULL;
         rc = VINF_SUCCESS;
     }
     else if (RT_FAILURE(rc))
-        return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
+        return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
     else if (!*pszCustBinFile)
     {
@@ -3179,7 +3272,7 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
                 /*
                  * Allocate buffer for the custom table binary data.
                  */
-                pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, pThis->cbCustBin);
+                pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbCustBin);
                 if (pThis->pu8CustBin)
                 {
                     rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
@@ -3327,7 +3420,7 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
     /*
      * Register the saved state.
      */
-    rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
+    rc = PDMDevHlpSSMRegister(pDevIns, 7, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
     if (RT_FAILURE(rc))
         return rc;
 
diff --git a/src/VBox/Devices/PC/DevSMC.cpp b/src/VBox/Devices/PC/DevSMC.cpp
deleted file mode 100644
index 8844fe9..0000000
--- a/src/VBox/Devices/PC/DevSMC.cpp
+++ /dev/null
@@ -1,630 +0,0 @@
-/* $Id: DevSMC.cpp $ */
-/** @file
- * DevSMC - SMC device emulation.
- *
- * @todo Rainy day: Rewrite from scratch!!
- */
-
-/*
- * Copyright (C) 2006-2012 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.
- * --------------------------------------------------------------------
- *
- * This code is based on:
- *
- *  Apple SMC controller
- *
- *  Copyright (c) 2007 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * *****************************************************************
- *
- * In all Intel-based Apple hardware there is an SMC chip to control the
- * backlight, fans and several other generic device parameters. It also
- * contains the magic keys used to dongle Mac OS X to the device.
- *
- * This driver was mostly created by looking at the Linux AppleSMC driver
- * implementation and does not support IRQ.
- *
- */
-
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_SMC
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/log.h>
-#include <VBox/vmm/stam.h>
-#include <iprt/assert.h>
-#include <iprt/string.h>
-#ifdef IN_RING0
-# include <iprt/asm-amd64-x86.h>
-# include <iprt/once.h>
-# include <iprt/thread.h>
-#endif
-
-#include "VBoxDD2.h"
-
-
-/*******************************************************************************
-*   Defined Constants And Macros                                               *
-*******************************************************************************/
-/* data port used by Apple SMC */
-#define APPLESMC_DATA_PORT      0x300
-/* command/status port used by Apple SMC */
-#define APPLESMC_CMD_PORT       0x304
-#define APPLESMC_NR_PORTS       32 /* 0x300-0x31f */
-#define APPLESMC_MAX_DATA_LENGTH 32
-
-#define APPLESMC_READ_CMD       0x10
-#define APPLESMC_WRITE_CMD      0x11
-#define APPLESMC_GET_KEY_BY_INDEX_CMD   0x12
-#define APPLESMC_GET_KEY_TYPE_CMD       0x13
-
-/** The version of the saved state. */
-#define SMC_SAVED_STATE_VERSION 1
-
-/** The ring-0 operation number that attempts to get OSK0 and OSK1 from the real
- *  SMC. */
-#define SMC_CALLR0_READ_OSK     1
-
-/*******************************************************************************
-*   Structures and Typedefs                                                    *
-*******************************************************************************/
-typedef struct AppleSMCData
-{
-    uint8_t       len;
-    const char    *key;
-    const char    *data;
-} AppleSMCData;
-
-
-typedef struct
-{
-    PPDMDEVINSR3   pDevIns;
-
-    uint8_t cmd;
-    uint8_t status;
-    uint8_t key[4];
-    uint8_t read_pos;
-    uint8_t data_len;
-    uint8_t data_pos;
-    uint8_t data[255];
-
-    /** The OSK0 value. This is currently only used in the constructor. */
-    uint8_t abOsk0[32];
-    /** The OSK1 value. This is currently only used in the constructor */
-    uint8_t abOsk1[32];
-} SMCState;
-
-/*******************************************************************************
-*   Global Variables                                                           *
-*******************************************************************************/
-#ifdef IN_RING3
-static char osk[64];
-
-/* See http://www.mactel-linux.org/wiki/AppleSMC */
-static struct AppleSMCData data[] =
-{
-    {6, "REV ", "\0x01\0x13\0x0f\0x00\0x00\0x03"},
-    {32,"OSK0", osk },
-    {32,"OSK1", osk+32 },
-    {1, "NATJ",  "\0" },
-    {1, "MSSP",  "\0" },
-    {1, "MSSD",  "\0x3" },
-    {1, "NTOK",  "\0"},
-    {0, NULL,    NULL }
-};
-#endif /* IN_RING3 */
-#ifdef IN_RING0
-/** Do once for the SMC ring-0 static data (g_abOsk0, g_abOsk1, g_fHaveOsk).  */
-static RTONCE   g_SmcR0Once = RTONCE_INITIALIZER;
-/** Indicates whether we've successfully queried the OSK* keys. */
-static bool     g_fHaveOsk = false;
-/** The OSK0 value.   */
-static uint8_t  g_abOsk0[32];
-/** The OSK1 value.  */
-static uint8_t  g_abOsk1[32];
-#endif /* IN_RING0 */
-
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-
-#ifdef IN_RING0
-
-/**
- * Waits for the specified status on the host SMC.
- *
- * @returns success indicator.
- * @param   bStatus             The desired status.
- * @param   pszWhat             What we're currently doing. For the log.
- */
-static bool devR0SmcWaitHostStatus(uint8_t bStatus, const char *pszWhat)
-{
-    uint8_t bCurStatus;
-    for (uint32_t cMsSleep = 1; cMsSleep <= 64; cMsSleep <<= 1)
-    {
-        RTThreadSleep(cMsSleep);
-        bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
-        if ((bCurStatus & 0xf) == bStatus)
-            return true;
-    }
-
-    LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", pszWhat, bCurStatus, bStatus));
-    return false;
-}
-
-/**
- * Reads a key by name from the host SMC.
- *
- * @returns success indicator.
- * @param   pszName             The key name, must be exactly 4 chars long.
- * @param   pbBuf               The output buffer.
- * @param   cbBuf               The buffer size. Max 32 bytes.
- */
-static bool devR0SmcQueryHostKey(const char *pszName, uint8_t *pbBuf, size_t cbBuf)
-{
-    Assert(strlen(pszName) == 4);
-    Assert(cbBuf <= 32);
-    Assert(cbBuf > 0);
-
-    /*
-     * Issue the READ command.
-     */
-    uint32_t cMsSleep = 1;
-    for (;;)
-    {
-        ASMOutU8(APPLESMC_CMD_PORT, APPLESMC_READ_CMD);
-        RTThreadSleep(cMsSleep);
-        uint8_t bCurStatus = ASMInU8(APPLESMC_CMD_PORT);
-        if ((bCurStatus & 0xf) == 0xc)
-            break;
-        cMsSleep <<= 1;
-        if (cMsSleep > 64)
-        {
-            LogRel(("devR0Smc: %s: bCurStatus=%#x, wanted %#x.\n", "cmd", bCurStatus, 0xc));
-            return false;
-        }
-    }
-
-    /*
-     * Send it the key.
-     */
-    for (unsigned off = 0; off < 4; off++)
-    {
-        ASMOutU8(APPLESMC_DATA_PORT, pszName[off]);
-        if (!devR0SmcWaitHostStatus(4, "key"))
-            return false;
-    }
-
-    /*
-     * The desired amount of output.
-     */
-    ASMOutU8(APPLESMC_DATA_PORT, (uint8_t)cbBuf);
-
-    /*
-     * Read the output.
-     */
-    for (size_t off = 0; off < cbBuf; off++)
-    {
-        if (!devR0SmcWaitHostStatus(5, off ? "data" : "len"))
-            return false;
-        pbBuf[off] = ASMInU8(APPLESMC_DATA_PORT);
-    }
-
-    return true;
-}
-
-/**
- * RTOnce callback that initializes g_fHaveOsk, g_abOsk0 and g_abOsk1.
- *
- * @returns VINF_SUCCESS.
- * @param   pvUserIgnored     Ignored.
- */
-static DECLCALLBACK(int) devR0SmcInitOnce(void *pvUserIgnored)
-{
-    g_fHaveOsk = devR0SmcQueryHostKey("OSK0", &g_abOsk0[0], sizeof(g_abOsk0))
-              && devR0SmcQueryHostKey("OSK1", &g_abOsk1[0], sizeof(g_abOsk1));
-
-    NOREF(pvUserIgnored);
-    return VINF_SUCCESS;
-}
-
-/**
- * @interface_method_impl{FNPDMDEVREQHANDLERR0}
- */
-PDMBOTHCBDECL(int) devR0SmcReqHandler(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)
-{
-    SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-    int       rc    = VERR_INVALID_FUNCTION;
-
-    if (uOperation == SMC_CALLR0_READ_OSK)
-    {
-        rc = RTOnce(&g_SmcR0Once, devR0SmcInitOnce, NULL);
-        if (   RT_SUCCESS(rc)
-            && g_fHaveOsk)
-        {
-            AssertCompile(sizeof(g_abOsk0) == sizeof(pThis->abOsk0));
-            AssertCompile(sizeof(g_abOsk1) == sizeof(pThis->abOsk1));
-            memcpy(pThis->abOsk0, g_abOsk0, sizeof(pThis->abOsk0));
-            memcpy(pThis->abOsk1, g_abOsk1, sizeof(pThis->abOsk1));
-        }
-    }
-    return rc;
-}
-
-#endif /* IN_RING0 */
-#ifdef IN_RING3
-
-/**
- * Saves a state of the SMC device.
- *
- * @returns VBox status code.
- * @param   pDevIns     The device instance.
- * @param   pSSMHandle  The handle to save the state to.
- */
-static DECLCALLBACK(int) smcSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
-{
-    SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-
-    /** @todo: implement serialization */
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Loads a SMC device state.
- *
- * @returns VBox status code.
- * @param   pDevIns     The device instance.
- * @param   pSSMHandle  The handle to the saved state.
- * @param   uVersion    The data unit version number.
- * @param   uPass       The data pass.
- */
-static DECLCALLBACK(int) smcLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
-{
-    SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-
-    if (uVersion != SMC_SAVED_STATE_VERSION)
-        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
-    Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
-
-    /** @todo: implement serialization */
-    return VINF_SUCCESS;
-}
-
-/**
- * Reset notification.
- *
- * @returns VBox status.
- * @param   pDevIns     The device instance data.
- */
-static DECLCALLBACK(void) smcReset(PPDMDEVINS pDevIns)
-{
-    SMCState *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-    LogFlow(("smcReset: \n"));
-}
-
-
-/**
- * Info handler, device version.
- *
- * @param   pDevIns     Device instance which registered the info.
- * @param   pHlp        Callback functions for doing output.
- * @param   pszArgs     Argument string. Optional and specific to the handler.
- */
-static DECLCALLBACK(void) smcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
-    SMCState   *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-}
-
-
-static void applesmc_fill_data(SMCState *s)
-{
-    struct AppleSMCData *d;
-    for (d=data; d->len; d++)
-    {
-        uint32_t key_data = *((uint32_t*)d->key);
-        uint32_t key_current = *((uint32_t*)s->key);
-        if (key_data == key_current)
-        {
-            Log(("APPLESMC: Key matched (%s Len=%d Data=%s)\n", d->key, d->len, d->data));
-            memcpy(s->data, d->data, d->len);
-            return;
-        }
-    }
-}
-
-/**
- * Port I/O Handler for IN operations.
- *
- * @returns VBox status code.
- *
- * @param   pDevIns     The device instance.
- * @param   pvUser      User argument - ignored.
- * @param   uPort       Port number used for the IN operation.
- * @param   pu32        Where to store the result.
- * @param   cb          Number of bytes read.
- */
-PDMBOTHCBDECL(int) smcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
-{
-    SMCState * s = PDMINS_2_DATA(pDevIns, SMCState *);
-    uint8_t retval = 0;
-
-    NOREF(pvUser);
-    Log(("SMC port read: %x (%d)\n", Port, cb));
-
-    /** @todo: status code? */
-    if (cb != 1)
-        return VERR_IOM_IOPORT_UNUSED;
-
-    switch (Port)
-    {
-        case APPLESMC_CMD_PORT:
-        {
-            retval = s->status;
-            break;
-        }
-        case APPLESMC_DATA_PORT:
-        {
-            switch (s->cmd) {
-                case APPLESMC_READ_CMD:
-                    if(s->data_pos < s->data_len)
-                    {
-                        retval = s->data[s->data_pos];
-                        Log(("APPLESMC: READ_DATA[%d] = %#hhx\n", s->data_pos, retval));
-                        s->data_pos++;
-                        if(s->data_pos == s->data_len)
-                        {
-                            s->status = 0x00;
-                            Log(("APPLESMC: EOF\n"));
-                        }
-                        else
-                            s->status = 0x05;
-                    }
-            }
-            break;
-        }
-    }
-
-    *pu32 = retval;
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Port I/O Handler for OUT operations.
- *
- * @returns VBox status code.
- *
- * @param   pDevIns     The device instance.
- * @param   pvUser      User argument - ignored.
- * @param   uPort       Port number used for the IN operation.
- * @param   u32         The value to output.
- * @param   cb          The value size in bytes.
- */
-PDMBOTHCBDECL(int) smcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
-{
-    SMCState* s = PDMINS_2_DATA(pDevIns, SMCState *);
-
-    NOREF(pvUser);
-
-    Log(("SMC port write: %x (%d) %x\n", Port, cb, u32));
-    /** @todo: status code? */
-    if (cb != 1)
-        return VINF_SUCCESS;
-
-    switch (Port)
-    {
-        case APPLESMC_CMD_PORT:
-        {
-            switch (u32)
-            {
-                case APPLESMC_READ_CMD:
-                    s->status = 0x0c;
-                    break;
-            }
-            s->cmd = u32;
-            s->read_pos = 0;
-            s->data_pos = 0;
-            break;
-        }
-        case APPLESMC_DATA_PORT:
-        {
-            switch(s->cmd)
-            {
-                case APPLESMC_READ_CMD:
-                    if (s->read_pos < 4)
-                    {
-                        s->key[s->read_pos] = u32;
-                        s->status = 0x04;
-                    }
-                    else
-                    if (s->read_pos == 4)
-                    {
-                        s->data_len = u32;
-                        s->status = 0x05;
-                        s->data_pos = 0;
-                        Log(("APPLESMC: Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], u32));
-                        applesmc_fill_data(s);
-                    }
-                    s->read_pos++;
-                    break;
-            }
-        }
-    }
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
-static DECLCALLBACK(int) smcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
-    SMCState   *pThis = PDMINS_2_DATA(pDevIns, SMCState *);
-    Assert(iInstance == 0);
-
-    /*
-     * Store state.
-     */
-    pThis->pDevIns = pDevIns;
-
-    /*
-     * Validate and read the configuration.
-     */
-    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceKey|GetKeyFromRealSMC", "");
-
-    /*
-     * Read the DeviceKey config value.
-     */
-    char *pszDeviceKey;
-    int rc = CFGMR3QueryStringAllocDef(pCfg, "DeviceKey", &pszDeviceKey, "");
-    if (RT_FAILURE(rc))
-        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
-                                   N_("Configuration error: Querying \"DeviceKey\" as a string failed"));
-
-    size_t cchDeviceKey = strlen(pszDeviceKey);
-    if (cchDeviceKey > 0)
-        memcpy(&pThis->abOsk0[0], pszDeviceKey, RT_MIN(cchDeviceKey, sizeof(pThis->abOsk0)));
-    if (cchDeviceKey > sizeof(pThis->abOsk0))
-        memcpy(&pThis->abOsk1[0], &pszDeviceKey[sizeof(pThis->abOsk0)],
-               RT_MIN(cchDeviceKey - sizeof(pThis->abOsk0), sizeof(pThis->abOsk1)));
-
-    MMR3HeapFree(pszDeviceKey);
-
-    /*
-     * Query the key from the real hardware if asked to do so.
-     */
-    bool fGetKeyFromRealSMC;
-    rc = CFGMR3QueryBoolDef(pCfg, "GetKeyFromRealSMC", &fGetKeyFromRealSMC, false);
-    if (RT_FAILURE(rc))
-        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
-                                   N_("Configuration error: Querying \"GetKeyFromRealSMC\" as a boolean failed"));
-    if (fGetKeyFromRealSMC)
-    {
-        rc = PDMDevHlpCallR0(pDevIns, SMC_CALLR0_READ_OSK, 0 /*u64Arg*/);
-        if (RT_FAILURE(rc))
-            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
-                                       N_("Failed to query SMC value from the host"));
-    }
-
-    /*
-     * For practical/historical reasons, the OSK[0|1] data is stored in a
-     * global buffer in ring-3.
-     */
-    AssertCompile(sizeof(osk) == sizeof(pThis->abOsk0) + sizeof(pThis->abOsk1));
-    AssertCompile(sizeof(char) == sizeof(uint8_t));
-    memcpy(osk, pThis->abOsk0, sizeof(pThis->abOsk0));
-    memcpy(&osk[sizeof(pThis->abOsk0)], pThis->abOsk1, sizeof(pThis->abOsk1));
-
-    /*
-     * Register the IO ports.
-     */
-    rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_DATA_PORT, 1, NULL,
-                                 smcIOPortWrite, smcIOPortRead,
-                                 NULL, NULL, "SMC Data");
-    if (RT_FAILURE(rc))
-        return rc;
-    rc = PDMDevHlpIOPortRegister(pDevIns, APPLESMC_CMD_PORT, 1, NULL,
-                                 smcIOPortWrite, smcIOPortRead,
-                                 NULL, NULL, "SMC Commands");
-    if (RT_FAILURE(rc))
-        return rc;
-
-    /* Register saved state management */
-    rc = PDMDevHlpSSMRegister(pDevIns, SMC_SAVED_STATE_VERSION, sizeof(*pThis), smcSaveExec, smcLoadExec);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    /*
-     * Initialize the device state.
-     */
-    smcReset(pDevIns);
-
-    /**
-     * @todo: Register statistics.
-     */
-    PDMDevHlpDBGFInfoRegister(pDevIns, "smc", "Display SMC status. (no arguments)", smcInfo);
-
-    return VINF_SUCCESS;
-}
-
-/**
- * The device registration structure.
- */
-const PDMDEVREG g_DeviceSMC =
-{
-    /* u32Version */
-    PDM_DEVREG_VERSION,
-    /* szName */
-    "smc",
-    /* szRCMod */
-    "VBoxDD2GC.gc",
-    /* szR0Mod */
-    "VBoxDD2R0.r0",
-    /* pszDescription */
-    "System Management Controller (SMC) Device",
-    /* fFlags */
-    PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36| PDM_DEVREG_FLAGS_R0,
-    /* fClass */
-    PDM_DEVREG_CLASS_MISC,
-    /* cMaxInstances */
-    1,
-    /* cbInstance */
-    sizeof(SMCState),
-    /* pfnConstruct */
-    smcConstruct,
-    /* pfnDestruct */
-    NULL,
-    /* pfnRelocate */
-    NULL,
-    /* pfnMemSetup */
-    NULL,
-    /* pfnPowerOn */
-    NULL,
-    /* pfnReset */
-    smcReset,
-    /* pfnSuspend */
-    NULL,
-    /* pfnResume */
-    NULL,
-    /* pfnAttach */
-    NULL,
-    /* pfnDetach */
-    NULL,
-    /* pfnQueryInterface. */
-    NULL,
-    /* pfnInitComplete */
-    NULL,
-    /* pfnPowerOff */
-    NULL,
-    /* pfnSoftReset */
-    NULL,
-    /* u32VersionEnd */
-    PDM_DEVREG_VERSION
-};
-
-#endif /* IN_RING3 */
-
-#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/Storage/DevAHCI.cpp b/src/VBox/Devices/Storage/DevAHCI.cpp
index c903604..d7e9911 100644
--- a/src/VBox/Devices/Storage/DevAHCI.cpp
+++ b/src/VBox/Devices/Storage/DevAHCI.cpp
@@ -1077,6 +1077,23 @@ static void ahciPortResetFinish(PAHCIPort pAhciPort)
     else
         pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
 
+    /* We received a COMINIT from the device. Tell the guest. */
+    ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
+    pAhciPort->regSERR |= AHCI_PORT_SERR_X;
+    pAhciPort->regTFD  |= ATA_STAT_BUSY;
+
+    if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
+    {
+        ahciPostFirstD2HFisIntoMemory(pAhciPort);
+        ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
+
+        if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
+        {
+            int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
+            AssertRC(rc);
+        }
+    }
+
     pAhciPort->regSSTS = (0x01 << 8)  | /* Interface is active. */
                          (0x03 << 0);   /* Device detected and communication established. */
 
@@ -1096,23 +1113,6 @@ static void ahciPortResetFinish(PAHCIPort pAhciPort)
             break;
     }
 
-    /* We received a COMINIT from the device. Tell the guest. */
-    ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
-    pAhciPort->regSERR |= AHCI_PORT_SERR_X;
-    pAhciPort->regTFD  |= ATA_STAT_BUSY;
-
-    if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
-    {
-        ahciPostFirstD2HFisIntoMemory(pAhciPort);
-        ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
-
-        if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
-        {
-            int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
-            AssertRC(rc);
-        }
-    }
-
     ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
 }
 #endif
@@ -1704,6 +1704,9 @@ static int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
     if (rc != VINF_SUCCESS)
         return rc;
 
+    /* Update interrupt status register first. */
+    ahci->regHbaIs |= ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
+
     if (u32Value > 0)
     {
         /*
@@ -6738,7 +6741,11 @@ static DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
 
                         rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
                         if (RT_FAILURE(rc))
+                        {
+                            /* In case we can't allocate enough memory fail the request with an overflow error. */
                             AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
+                            pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
+                        }
                     }
 
                     if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
@@ -6936,6 +6943,7 @@ static DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, con
         pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
         pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
         pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
+        pHlp->pfnPrintf(pHlp, "PortTasksNew=%#x\n", pThisPort->u32TasksNew);
         pHlp->pfnPrintf(pHlp, "\n");
     }
 }
diff --git a/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp b/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
index 9f53298..72913f3 100644
--- a/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
+++ b/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
@@ -798,6 +798,15 @@ static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
     return rc;
 }
 
+/** @copydoc PDMIMEDIA::pfnReadPcBios */
+static DECLCALLBACK(int) drvdiskintReadPcBios(PPDMIMEDIA pInterface,
+                                              uint64_t off, void *pvBuf, size_t cbRead)
+{
+    PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
+
+    return pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
+}
+
 /** @copydoc PDMIMEDIA::pfnWrite */
 static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
                                          uint64_t off, const void *pvBuf,
@@ -1377,6 +1386,7 @@ static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg,
 
     /* IMedia */
     pThis->IMedia.pfnRead                = drvdiskintRead;
+    pThis->IMedia.pfnReadPcBios          = drvdiskintReadPcBios;
     pThis->IMedia.pfnWrite               = drvdiskintWrite;
     pThis->IMedia.pfnFlush               = drvdiskintFlush;
     pThis->IMedia.pfnGetSize             = drvdiskintGetSize;
diff --git a/src/VBox/Devices/USB/DevOHCI.cpp b/src/VBox/Devices/USB/DevOHCI.cpp
index f832459..c21fddb 100644
--- a/src/VBox/Devices/USB/DevOHCI.cpp
+++ b/src/VBox/Devices/USB/DevOHCI.cpp
@@ -368,6 +368,8 @@ typedef struct OHCI
     R3PTRTYPE(PPDMTHREAD) hThreadFrame;
     /** Event semaphore to interact with the framer thread. */
     R3PTRTYPE(RTSEMEVENT) hSemEventFrame;
+    /** Event semaphore to release the thread waiting for the framer thread to stop. */
+    R3PTRTYPE(RTSEMEVENTMULTI) hSemEventFrameStopped;
     /** Flag whether the framer thread should processing frames. */
     volatile bool         fBusStarted;
     /** Alignment. */
@@ -783,6 +785,7 @@ RT_C_DECLS_BEGIN
 /* Update host controller state to reflect a device attach */
 static void                 rhport_power(POHCIROOTHUB pRh, unsigned iPort, bool fPowerUp);
 static void                 ohciBusResume(POHCI ohci, bool fHardware);
+static void                 ohciBusStop(POHCI pThis);
 
 static DECLCALLBACK(void)   ohciRhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
 static DECLCALLBACK(bool)   ohciRhXferError(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
@@ -1101,6 +1104,9 @@ static void ohciDoReset(POHCI pThis, uint32_t fNewMode, bool fResetOnLinux)
     Log(("ohci: %s reset%s\n", fNewMode == OHCI_USB_RESET ? "hardware" : "software",
          fResetOnLinux ? " (reset on linux)" : ""));
 
+    /* Stop the bus in any case, disabling walking the lists. */
+    ohciBusStop(pThis);
+
     /*
      * Cancel all outstanding URBs.
      *
@@ -1117,6 +1123,9 @@ static void ohciDoReset(POHCI pThis, uint32_t fNewMode, bool fResetOnLinux)
         pThis->ctl |= OHCI_CTL_RWC;                     /* We're the firmware, set RemoteWakeupConnected. */
     else
         pThis->ctl &= OHCI_CTL_IR | OHCI_CTL_RWC;       /* IR and RWC are preserved on software reset. */
+
+    /* Clear the HCFS bits first to make setting the new state work. */
+    pThis->ctl &= ~OHCI_CTL_HCFS;
     pThis->ctl |= fNewMode;
     pThis->status = 0;
     pThis->intr_status = 0;
@@ -3826,7 +3835,12 @@ static DECLCALLBACK(int) ohciR3ThreadFrame(PPDMDEVINS pDevIns, PPDMTHREAD pThrea
         while (   !ASMAtomicReadBool(&pThis->fBusStarted)
                && pThread->enmState == PDMTHREADSTATE_RUNNING
                && RT_SUCCESS(rc))
+        {
+            /* Signal the waiter that we are stopped now. */
+            rc = RTSemEventMultiSignal(pThis->hSemEventFrameStopped);
+            AssertRC(rc);
             rc = RTSemEventWait(pThis->hSemEventFrame, RT_INDEFINITE_WAIT);
+        }
 
         AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc), rc);
         if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
@@ -3895,8 +3909,9 @@ static void ohciBusStart(POHCI pThis)
     Log(("ohci: %s: Bus started\n", pThis->PciDev.name));
 
     pThis->SofTime = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns));
-    ASMAtomicXchgBool(&pThis->fBusStarted, true);
-    RTSemEventSignal(pThis->hSemEventFrame);
+    bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, true);
+    if (!fBusActive)
+        RTSemEventSignal(pThis->hSemEventFrame);
 }
 
 /**
@@ -3904,8 +3919,19 @@ static void ohciBusStart(POHCI pThis)
  */
 static void ohciBusStop(POHCI pThis)
 {
-    ASMAtomicXchgBool(&pThis->fBusStarted, false);
-    RTSemEventSignal(pThis->hSemEventFrame);
+    bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, false);
+    if (fBusActive)
+    {
+        int rc = RTSemEventMultiReset(pThis->hSemEventFrameStopped);
+        AssertRC(rc);
+
+        /* Signal the frame thread to stop. */
+        RTSemEventSignal(pThis->hSemEventFrame);
+
+        /* Wait for signal from the thrad that it stopped. */
+        rc = RTSemEventMultiWait(pThis->hSemEventFrameStopped, RT_INDEFINITE_WAIT);
+        AssertRC(rc);
+    }
     VUSBIDevPowerOff(pThis->RootHub.pIDev);
 }
 
@@ -5452,7 +5478,6 @@ static DECLCALLBACK(void) ohciR3Reset(PPDMDEVINS pDevIns)
      * Important: Don't confuse UsbReset with hardware reset. Hardware reset is
      *            just one way of getting into the UsbReset state.
      */
-    ohciBusStop(pThis);
     ohciDoReset(pThis, OHCI_USB_RESET, true /* reset devices */);
 }
 
@@ -5569,7 +5594,10 @@ static DECLCALLBACK(int) ohciR3Destruct(PPDMDEVINS pDevIns)
     /*
      * Destroy event sempahores.
      */
-    RTSemEventDestroy(pThis->hSemEventFrame);
+    if (pThis->hSemEventFrame)
+        RTSemEventDestroy(pThis->hSemEventFrame);
+    if (pThis->hSemEventFrameStopped)
+        RTSemEventMultiDestroy(pThis->hSemEventFrameStopped);
     if (RTCritSectIsInitialized(&pThis->CritSect))
         RTCritSectDelete(&pThis->CritSect);
     PDMR3CritSectDelete(&pThis->CsIrq);
@@ -5727,6 +5755,9 @@ static DECLCALLBACK(int) ohciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
     rc = RTSemEventCreate(&pThis->hSemEventFrame);
     AssertRCReturn(rc, rc);
 
+    rc = RTSemEventMultiCreate(&pThis->hSemEventFrameStopped);
+    AssertRCReturn(rc, rc);
+
     rc = RTCritSectInit(&pThis->CritSect);
     if (RT_FAILURE(rc))
         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
diff --git a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
index 6db66b2..c9487c9 100644
--- a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
+++ b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
@@ -608,8 +608,11 @@ static DECLCALLBACK(int) vusbRhCancelAllUrbsWorker(PVUSBDEV pDev)
 {
     /*
      * Cancel the URBS.
+     *
+     * Not using th CritAsyncUrbs critical section here is safe
+     * as the I/O thread is the only thread accessing this struture at the
+     * moment.
      */
-    RTCritSectEnter(&pDev->CritSectAsyncUrbs);
     PVUSBURB pUrb = pDev->pAsyncUrbHead;
 
     while (pUrb)
@@ -619,7 +622,6 @@ static DECLCALLBACK(int) vusbRhCancelAllUrbsWorker(PVUSBDEV pDev)
         vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
         pUrb = pNext;
     }
-    RTCritSectLeave(&pDev->CritSectAsyncUrbs);
 
     return VINF_SUCCESS;
 }
diff --git a/src/VBox/Devices/USB/VUSBDevice.cpp b/src/VBox/Devices/USB/VUSBDevice.cpp
index 4790fcb..f01eb2e 100644
--- a/src/VBox/Devices/USB/VUSBDevice.cpp
+++ b/src/VBox/Devices/USB/VUSBDevice.cpp
@@ -34,11 +34,6 @@
 #include "VUSBInternal.h"
 
 
-/** Asserts that the give device state is valid. */
-#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
-    AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
-
-
 /*******************************************************************************
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
@@ -216,6 +211,31 @@ static void map_interface(PVUSBDEV pDev, PCVUSBDESCINTERFACEEX pIfDesc)
     }
 }
 
+
+/**
+ * Worker that resets the pipe data on select config and detach.
+ *
+ * This leaves the critical section unmolested
+ *
+ * @param   pPipe               The pipe which data should be reset.
+ */
+static void vusbDevResetPipeData(PVUSBPIPE pPipe)
+{
+    vusbMsgFreeExtraData(pPipe->pCtrl);
+    pPipe->pCtrl = NULL;
+
+    if (pPipe->hReadAhead)
+    {
+        vusbReadAheadStop(pPipe->hReadAhead);
+        pPipe->hReadAhead = NULL;
+    }
+
+    RT_ZERO(pPipe->in);
+    RT_ZERO(pPipe->out);
+    pPipe->async = 0;
+}
+
+
 bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
 {
     LogFlow(("vusbDevDoSelectConfig: pDev=%p[%s] pCfgDesc=%p:{.iConfiguration=%d}\n",
@@ -226,13 +246,8 @@ bool vusbDevDoSelectConfig(PVUSBDEV pDev, PCVUSBDESCCONFIGEX pCfgDesc)
      */
     unsigned i;
     for (i = 0; i < VUSB_PIPE_MAX; i++)
-    {
         if (i != VUSB_PIPE_DEFAULT)
-        {
-            vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
-            memset(&pDev->aPipes[i], 0, sizeof(pDev->aPipes[i]));
-        }
-    }
+            vusbDevResetPipeData(&pDev->aPipes[i]);
     memset(pDev->paIfStates, 0, pCfgDesc->Core.bNumInterfaces * sizeof(pDev->paIfStates[0]));
 
     /*
@@ -292,7 +307,7 @@ static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
      * Check that the device is in a valid state.
      * (The caller has already checked that it's not being reset.)
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState == VUSB_DEVICE_STATE_DEFAULT)
     {
         LogFlow(("vusbDevStdReqSetConfig: %s: default dev state !!?\n", pDev->pUsbIns->pszName));
@@ -307,9 +322,9 @@ static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
     }
 
     if (iCfg == 0)
-        pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
+        vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
     else
-        pDev->enmState = VUSB_DEVICE_STATE_CONFIGURED;
+        vusbDevSetState(pDev, VUSB_DEVICE_STATE_CONFIGURED);
     if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
     {
         int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5,
@@ -342,7 +357,7 @@ static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
      * Check that the device is in a valid state.
      * (The caller has already checked that it's not being reset.)
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (    enmState != VUSB_DEVICE_STATE_CONFIGURED
         &&  enmState != VUSB_DEVICE_STATE_ADDRESS)
     {
@@ -357,7 +372,7 @@ static bool vusbDevStdReqGetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
     }
 
     uint8_t iCfg;
-    if (pDev->enmState == VUSB_DEVICE_STATE_ADDRESS)
+    if (enmState == VUSB_DEVICE_STATE_ADDRESS)
         iCfg = 0;
     else
         iCfg = pDev->pCurCfgDesc->Core.bConfigurationValue;
@@ -384,7 +399,7 @@ static bool vusbDevStdReqGetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
      * Check that the device is in a valid state.
      * (The caller has already checked that it's not being reset.)
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
     {
         LogFlow(("vusbDevStdReqGetInterface: error: %s: invalid device state %d!!!\n", pDev->pUsbIns->pszName, enmState));
@@ -430,7 +445,7 @@ static bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
      * Check that the device is in a valid state.
      * (The caller has already checked that it's not being reset.)
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState != VUSB_DEVICE_STATE_CONFIGURED)
     {
         LogFlow(("vusbDevStdReqSetInterface: error: %s: invalid device state %d !!!\n", pDev->pUsbIns->pszName, enmState));
@@ -492,7 +507,7 @@ static bool vusbDevStdReqSetAddress(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
      * Check that the device is in a valid state.
      * (The caller has already checked that it's not being reset.)
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (    enmState != VUSB_DEVICE_STATE_DEFAULT
         &&  enmState != VUSB_DEVICE_STATE_ADDRESS)
     {
@@ -663,10 +678,10 @@ static void ReadCachedStringDesc(PCPDMUSBDESCCACHESTRING pString, uint8_t *pbBuf
     }
 
     VUSBDESCSTRING  StringDesc;
-    StringDesc.bLength          = sizeof(StringDesc) + cwc * sizeof(RTUTF16);
+    StringDesc.bLength          = (uint8_t)(sizeof(StringDesc) + cwc * sizeof(RTUTF16));
     StringDesc.bDescriptorType  = VUSB_DT_STRING;
     COPY_DATA(pbBuf, cbLeft, &StringDesc, sizeof(StringDesc));
-    COPY_DATA(pbBuf, cbLeft, wsz, cwc * sizeof(RTUTF16));
+    COPY_DATA(pbBuf, cbLeft, wsz, (uint32_t)cwc * sizeof(RTUTF16));
 
     /* updated the size of the output buffer. */
     *pcbBuf -= cbLeft;
@@ -683,7 +698,7 @@ static void ReadCachedLangIdDesc(PCPDMUSBDESCCACHELANG paLanguages, unsigned cLa
 
     VUSBDESCLANGID  LangIdDesc;
     size_t          cbDesc      = sizeof(LangIdDesc) + cLanguages * sizeof(paLanguages[0].idLang);
-    LangIdDesc.bLength          = RT_MIN(0xff, cbDesc);
+    LangIdDesc.bLength          = (uint8_t)RT_MIN(0xff, cbDesc);
     LangIdDesc.bDescriptorType  = VUSB_DT_STRING;
     COPY_DATA(pbBuf, cbLeft, &LangIdDesc, sizeof(LangIdDesc));
 
@@ -889,8 +904,7 @@ bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPoint, PVUSBSETUP pSetup, void
     /*
      * Check that the device is in a valid state.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
-    VUSBDEV_ASSERT_VALID_STATE(enmState);
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState == VUSB_DEVICE_STATE_RESET)
     {
         LogRel(("VUSB: %s: standard control message ignored, the device is resetting\n", pDev->pUsbIns->pszName));
@@ -974,7 +988,7 @@ void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
     /*
      * Check that the device is in a valid state.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     VUSBDEV_ASSERT_VALID_STATE(enmState);
     if (    enmState == VUSB_DEVICE_STATE_ATTACHED
         ||  enmState == VUSB_DEVICE_STATE_DETACHED)
@@ -1006,15 +1020,15 @@ void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address)
         if (pRh->pDefaultAddress != NULL)
         {
             vusbDevAddressUnHash(pRh->pDefaultAddress);
-            pRh->pDefaultAddress->enmState = VUSB_DEVICE_STATE_POWERED;
+            vusbDevSetState(pRh->pDefaultAddress, VUSB_DEVICE_STATE_POWERED);
             Log(("2 DEFAULT ADDRS\n"));
         }
 
         pRh->pDefaultAddress = pDev;
-        pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
+        vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
     }
     else
-        pDev->enmState = VUSB_DEVICE_STATE_ADDRESS;
+        vusbDevSetState(pDev, VUSB_DEVICE_STATE_ADDRESS);
 
     pDev->u8Address = u8Address;
     vusbDevAddressHash(pDev);
@@ -1130,7 +1144,7 @@ static DECLCALLBACK(int) vusbDevUrbIoThread(RTTHREAD hThread, void *pvUser)
 
     while (!ASMAtomicReadBool(&pDev->fTerminate))
     {
-        if (pDev->enmState != VUSB_DEVICE_STATE_RESET)
+        if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
             vusbUrbDoReapAsyncDev(pDev, RT_INDEFINITE_WAIT);
 
         /* Process any URBs waiting to be cancelled first. */
@@ -1218,23 +1232,13 @@ int vusbDevDetach(PVUSBDEV pDev)
 
     pDev->pHub->pOps->pfnDetach(pDev->pHub, pDev);
     pDev->i16Port = -1;
-    pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
+    vusbDevSetState(pDev, VUSB_DEVICE_STATE_DETACHED);
     pDev->pHub = NULL;
 
     /* Remove the configuration */
     pDev->pCurCfgDesc = NULL;
-    for (unsigned i = 0; i < VUSB_PIPE_MAX; i++)
-    {
-        vusbMsgFreeExtraData(pDev->aPipes[i].pCtrl);
-        RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
-
-        if (pDev->aPipes[i].hReadAhead)
-        {
-            vusbReadAheadStop(pDev->aPipes[i].hReadAhead);
-            pDev->aPipes[i].hReadAhead = NULL;
-        }
-    }
-    memset(pDev->aPipes, 0, sizeof(pDev->aPipes));
+    for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
+        vusbDevResetPipeData(&pDev->aPipes[i]);
     return VINF_SUCCESS;
 }
 
@@ -1251,9 +1255,9 @@ void vusbDevDestroy(PVUSBDEV pDev)
 
     /*
      * Deal with pending async reset.
+     * (anything but reset)
      */
-    if (pDev->enmState == VUSB_DEVICE_STATE_RESET)
-        pDev->enmState = VUSB_DEVICE_STATE_DEFAULT; /* anything but reset */
+    vusbDevSetStateCmp(pDev, VUSB_DEVICE_STATE_DEFAULT, VUSB_DEVICE_STATE_RESET);
 
     /*
      * Detach and free resources.
@@ -1263,6 +1267,11 @@ void vusbDevDestroy(PVUSBDEV pDev)
     RTMemFree(pDev->paIfStates);
     TMR3TimerDestroy(pDev->pResetTimer);
     pDev->pResetTimer = NULL;
+    for (unsigned i = 0; i < RT_ELEMENTS(pDev->aPipes); i++)
+    {
+        Assert(pDev->aPipes[i].pCtrl == NULL);
+        RTCritSectDelete(&pDev->aPipes[i].CritSectCtrl);
+    }
 
     /*
      * Destroy I/O thread and request queue last because they might still be used
@@ -1274,6 +1283,7 @@ void vusbDevDestroy(PVUSBDEV pDev)
     AssertRC(rc);
 
     RTCritSectDelete(&pDev->CritSectAsyncUrbs);
+    /* Not using vusbDevSetState() deliberately here because it would assert on the state. */
     pDev->enmState = VUSB_DEVICE_STATE_DESTROYED;
 }
 
@@ -1312,7 +1322,7 @@ static void vusbDevResetDone(PVUSBDEV pDev, int rc, PFNVUSBRESETDONE pfnDone, vo
     /*
      * Switch to the default state.
      */
-    pDev->enmState = VUSB_DEVICE_STATE_DEFAULT;
+    vusbDevSetState(pDev, VUSB_DEVICE_STATE_DEFAULT);
     pDev->u16Status = 0;
     vusbDevDoSelectConfig(pDev, &g_Config0);
     if (!vusbDevIsRh(pDev))
@@ -1405,7 +1415,7 @@ static int vusbDevResetWorker(PVUSBDEV pDev, bool fResetOnLinux, bool fUseTimer,
  *                          on the EMT thread.
  * @thread  EMT
  */
-DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
+DECLCALLBACK(int) vusbIDeviceReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
 {
     PVUSBDEV pDev = (PVUSBDEV)pDevice;
     Assert(!pfnDone || pVM);
@@ -1414,14 +1424,12 @@ DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSB
     /*
      * Only one reset operation at a time.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
-    VUSBDEV_ASSERT_VALID_STATE(enmState);
-    if (enmState == VUSB_DEVICE_STATE_RESET)
+    const VUSBDEVICESTATE enmStateOld = vusbDevSetState(pDev, VUSB_DEVICE_STATE_RESET);
+    if (enmStateOld == VUSB_DEVICE_STATE_RESET)
     {
         LogRel(("VUSB: %s: reset request is ignored, the device is already resetting!\n", pDev->pUsbIns->pszName));
         return VERR_VUSB_DEVICE_IS_RESETTING;
     }
-    pDev->enmState = VUSB_DEVICE_STATE_RESET;
 
     /*
      * First, cancel all async URBs.
@@ -1466,7 +1474,7 @@ DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSB
  * @returns VBox status code.
  * @param   pInterface      Pointer to the device interface structure.
  */
-DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
+DECLCALLBACK(int) vusbIDevicePowerOn(PVUSBIDEVICE pInterface)
 {
     PVUSBDEV pDev = (PVUSBDEV)pInterface;
     LogFlow(("vusbDevPowerOn: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1474,8 +1482,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
     /*
      * Check that the device is in a valid state.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
-    VUSBDEV_ASSERT_VALID_STATE(enmState);
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState == VUSB_DEVICE_STATE_DETACHED)
     {
         Log(("vusb: warning: attempt to power on detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1491,7 +1498,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
      * Do the job.
      */
     if (enmState == VUSB_DEVICE_STATE_ATTACHED)
-        pDev->enmState = VUSB_DEVICE_STATE_POWERED;
+        vusbDevSetState(pDev, VUSB_DEVICE_STATE_POWERED);
 
     return VINF_SUCCESS;
 }
@@ -1503,7 +1510,7 @@ DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface)
  * @returns VBox status code.
  * @param   pInterface      Pointer to the device interface structure.
  */
-DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
+DECLCALLBACK(int) vusbIDevicePowerOff(PVUSBIDEVICE pInterface)
 {
     PVUSBDEV pDev = (PVUSBDEV)pInterface;
     LogFlow(("vusbDevPowerOff: pDev=%p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1511,8 +1518,7 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
     /*
      * Check that the device is in a valid state.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
-    VUSBDEV_ASSERT_VALID_STATE(enmState);
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState == VUSB_DEVICE_STATE_DETACHED)
     {
         Log(("vusb: warning: attempt to power off detached device %p[%s]\n", pDev, pDev->pUsbIns->pszName));
@@ -1534,8 +1540,7 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
         VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, pInterface, 0);
     }
 
-    pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
-
+    vusbDevSetState(pDev, VUSB_DEVICE_STATE_ATTACHED);
     return VINF_SUCCESS;
 }
 
@@ -1546,9 +1551,9 @@ DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface)
  * @returns Device state.
  * @param   pInterface      Pointer to the device interface structure.
  */
-DECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface)
+DECLCALLBACK(VUSBDEVICESTATE) vusbIDeviceGetState(PVUSBIDEVICE pInterface)
 {
-    return ((PVUSBDEV)pInterface)->enmState;
+    return vusbDevGetState((PVUSBDEV)pInterface);
 }
 
 
@@ -1687,10 +1692,10 @@ int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns)
     Assert(!pDev->IDevice.pfnPowerOff);
     Assert(!pDev->IDevice.pfnGetState);
 
-    pDev->IDevice.pfnReset = vusbDevReset;
-    pDev->IDevice.pfnPowerOn = vusbDevPowerOn;
-    pDev->IDevice.pfnPowerOff = vusbDevPowerOff;
-    pDev->IDevice.pfnGetState = vusbDevGetState;
+    pDev->IDevice.pfnReset = vusbIDeviceReset;
+    pDev->IDevice.pfnPowerOn = vusbIDevicePowerOn;
+    pDev->IDevice.pfnPowerOff = vusbIDevicePowerOff;
+    pDev->IDevice.pfnGetState = vusbIDeviceGetState;
     pDev->pUsbIns = pUsbIns;
     pDev->pNext = NULL;
     pDev->pNextHash = NULL;
diff --git a/src/VBox/Devices/USB/VUSBInternal.h b/src/VBox/Devices/USB/VUSBInternal.h
index c9832d7..da10db6 100644
--- a/src/VBox/Devices/USB/VUSBInternal.h
+++ b/src/VBox/Devices/USB/VUSBInternal.h
@@ -169,8 +169,7 @@ typedef struct VUSBDEV
     PVUSBDEV            pNextHash;
     /** Pointer to the hub this device is attached to. */
     PVUSBHUB            pHub;
-    /** The device state.
-     * Only EMT changes this value. */
+    /** The device state. */
     VUSBDEVICESTATE volatile enmState;
 
     /** The device address. */
@@ -263,10 +262,6 @@ int vusbDevDetach(PVUSBDEV pDev);
 DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev);
 size_t vusbDevMaxInterfaces(PVUSBDEV dev);
 
-DECLCALLBACK(int) vusbDevReset(PVUSBIDEVICE pDevice, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM);
-DECLCALLBACK(int) vusbDevPowerOn(PVUSBIDEVICE pInterface);
-DECLCALLBACK(int) vusbDevPowerOff(PVUSBIDEVICE pInterface);
-DECLCALLBACK(VUSBDEVICESTATE) vusbDevGetState(PVUSBIDEVICE pInterface);
 void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address);
 bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf);
 
@@ -497,6 +492,13 @@ DECLINLINE(void) vusbUrbUnlink(PVUSBURB pUrb)
 # define vusbUrbAssert(pUrb) do {} while (0)
 #endif
 
+/**
+ * @def VUSBDEV_ASSERT_VALID_STATE
+ * Asserts that the give device state is valid.
+ */
+#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
+    AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
+
 /** Executes a function synchronously. */
 #define VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC RT_BIT_32(0)
 
@@ -533,6 +535,51 @@ DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev)
 }
 
 
+/**
+ * Returns the state of the USB device.
+ *
+ * @returns State of the USB device.
+ * @param   pDev    Pointer to the device.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevGetState(PVUSBDEV pDev)
+{
+    VUSBDEVICESTATE enmState = (VUSBDEVICESTATE)ASMAtomicReadU32((volatile uint32_t *)&pDev->enmState);
+    VUSBDEV_ASSERT_VALID_STATE(enmState);
+    return enmState;
+}
+
+
+/**
+ * Sets the given state for the USB device.
+ *
+ * @returns The old state of the device.
+ * @param   pDev     Pointer to the device.
+ * @param   enmState The new state to set.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevSetState(PVUSBDEV pDev, VUSBDEVICESTATE enmState)
+{
+    VUSBDEV_ASSERT_VALID_STATE(enmState);
+    VUSBDEVICESTATE enmStateOld = (VUSBDEVICESTATE)ASMAtomicXchgU32((volatile uint32_t *)&pDev->enmState, enmState);
+    VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+    return enmStateOld;
+}
+
+
+/**
+ * Compare and exchange the states for the given USB device.
+ *
+ * @returns true if the state was changed.
+ * @returns false if the state wasn't changed.
+ * @param   pDev           Pointer to the device.
+ * @param   enmStateNew    The new state to set.
+ * @param   enmStateOld    The old state to compare with.
+ */
+DECLINLINE(bool) vusbDevSetStateCmp(PVUSBDEV pDev, VUSBDEVICESTATE enmStateNew, VUSBDEVICESTATE enmStateOld)
+{
+    VUSBDEV_ASSERT_VALID_STATE(enmStateNew);
+    VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+    return ASMAtomicCmpXchgU32((volatile uint32_t *)&pDev->enmState, enmStateNew, enmStateOld);
+}
 
 /** Strings for the CTLSTAGE enum values. */
 extern const char * const g_apszCtlStates[4];
diff --git a/src/VBox/Devices/USB/VUSBUrb.cpp b/src/VBox/Devices/USB/VUSBUrb.cpp
index e1a5f3c..853c129 100644
--- a/src/VBox/Devices/USB/VUSBUrb.cpp
+++ b/src/VBox/Devices/USB/VUSBUrb.cpp
@@ -1834,7 +1834,7 @@ int vusbUrbSubmit(PVUSBURB pUrb)
     /*
      * Check that the device is in a valid state.
      */
-    const VUSBDEVICESTATE enmState = pDev->enmState;
+    const VUSBDEVICESTATE enmState = vusbDevGetState(pDev);
     if (enmState == VUSB_DEVICE_STATE_RESET)
     {
         LogRel(("VUSB: %s: power off ignored, the device is resetting!\n", pDev->pUsbIns->pszName));
@@ -1970,7 +1970,7 @@ void vusbUrbDoReapAsync(PVUSBURB pHead, RTMSINTERVAL cMillies)
         PVUSBDEV pDev = pUrb->VUsb.pDev;
 
         /* Don't touch resetting devices - paranoid safety precaution. */
-        if (pDev->enmState != VUSB_DEVICE_STATE_RESET)
+        if (vusbDevGetState(pDev) != VUSB_DEVICE_STATE_RESET)
         {
             /*
              * Reap most URBs pending on a single device.
diff --git a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
index 312c6b6..df05840 100644
--- a/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
+++ b/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
@@ -280,8 +280,9 @@ static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProxyDev, int iIf, bool fCon
  */
 static void usbProxyLinuxUrbLinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx)
 {
+    LogFlowFunc(("pDevLnx=%p pUrbLnx=%p\n", pDevLnx, pUrbLnx));
     Assert(RTCritSectIsOwner(&pDevLnx->CritSect));
-    Assert(!pUrbLnx->pSplitHead);
+    Assert(!pUrbLnx->pSplitHead || pUrbLnx->pSplitHead == pUrbLnx);
     RTListAppend(&pDevLnx->ListInFlight, &pUrbLnx->NodeList);
 }
 
@@ -293,6 +294,7 @@ static void usbProxyLinuxUrbLinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLN
  */
 static void usbProxyLinuxUrbUnlinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURBLNX pUrbLnx)
 {
+    LogFlowFunc(("pDevLnx=%p pUrbLnx=%p\n", pDevLnx, pUrbLnx));
     RTCritSectEnter(&pDevLnx->CritSect);
 
     /*
@@ -301,7 +303,6 @@ static void usbProxyLinuxUrbUnlinkInFlight(PUSBPROXYDEVLNX pDevLnx, PUSBPROXYURB
     Assert(!pUrbLnx->pSplitHead || pUrbLnx->pSplitHead == pUrbLnx);
 
     RTListNodeRemove(&pUrbLnx->NodeList);
-    pUrbLnx->pSplitHead = pUrbLnx->pSplitNext = NULL;
 
     RTCritSectLeave(&pDevLnx->CritSect);
 }
@@ -318,6 +319,8 @@ static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYUR
     PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
     PUSBPROXYURBLNX pUrbLnx;
 
+    LogFlowFunc(("pProxyDev=%p pSplitHead=%p\n", pProxyDev, pSplitHead));
+
     RTCritSectEnter(&pDevLnx->CritSect);
 
     /*
@@ -341,6 +344,7 @@ static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYUR
     pUrbLnx->pSplitNext = NULL;
     pUrbLnx->fCanceledBySubmit = false;
     pUrbLnx->fSplitElementReaped = false;
+    LogFlowFunc(("returns pUrbLnx=%p\n", pUrbLnx));
     return pUrbLnx;
 }
 
@@ -355,13 +359,13 @@ static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx
 {
     PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
 
-    RTCritSectEnter(&pDevLnx->CritSect);
+    LogFlowFunc(("pProxyDev=%p pUrbLnx=%p\n", pProxyDev, pUrbLnx));
 
     /*
      * Link it into the free list.
      */
+    RTCritSectEnter(&pDevLnx->CritSect);
     RTListAppend(&pDevLnx->ListFree, &pUrbLnx->NodeList);
-
     RTCritSectLeave(&pDevLnx->CritSect);
 }
 
@@ -376,6 +380,8 @@ static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLN
 {
     PUSBPROXYDEVLNX pDevLnx = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVLNX);
 
+    LogFlowFunc(("pProxyDev=%p pUrbLnx=%p\n", pProxyDev, pUrbLnx));
+
     RTCritSectEnter(&pDevLnx->CritSect);
 
     pUrbLnx = pUrbLnx->pSplitHead;
@@ -1305,6 +1311,8 @@ static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUS
     uint32_t            cbLeft = pCur->cbSplitRemaining;
     uint8_t             *pb = (uint8_t *)pCur->KUrb.buffer;
 
+    LogFlowFunc(("pProxyDev=%p pHead=%p pCur=%p\n", pProxyDev, pHead, pCur));
+
     Assert(cbLeft != 0);
     pNew = pCur->pSplitNext = usbProxyLinuxUrbAlloc(pProxyDev, pHead);
     if (!pNew)
@@ -1323,6 +1331,7 @@ static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUS
     cbLeft -= pNew->KUrb.buffer_length;
     Assert(cbLeft < INT32_MAX);
     pNew->cbSplitRemaining = cbLeft;
+    LogFlowFunc(("returns pNew=%p\n", pNew));
     return pNew;
 }
 
@@ -1522,6 +1531,7 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
             continue;
         if (errno == ENODEV)
         {
+            rc = RTErrConvertFromErrno(errno);
             Log(("usbProxyLinuxUrbQueue: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
             if (pUrb->enmType == VUSBXFERTYPE_MSG)
                 usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
@@ -1529,7 +1539,7 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
             RTCritSectLeave(&pDevLnx->CritSect);
             usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
             usbProxLinuxUrbUnplugged(pProxyDev);
-            return RTErrConvertFromErrno(errno);
+            return rc;
         }
 
         /*
@@ -1543,8 +1553,9 @@ static DECLCALLBACK(int) usbProxyLinuxUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB
         if (    errno == EINVAL
             &&  pUrb->cbData >= 8*_1K)
         {
+            rc = usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb);
             RTCritSectLeave(&pDevLnx->CritSect);
-            return usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb);
+            return rc;
         }
 
         Log(("usb-linux: Queue URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
@@ -1790,6 +1801,7 @@ static DECLCALLBACK(PVUSBURB) usbProxyLinuxUrbReap(PUSBPROXYDEV pProxyDev, RTMSI
                     pUrb->enmStatus = vusbProxyLinuxUrbGetStatus(pCur);
             }
             pUrb->cbData = pbEnd - &pUrb->abData[0];
+            usbProxyLinuxUrbUnlinkInFlight(pDevLnx, pUrbLnx);
             usbProxyLinuxUrbFreeSplitList(pProxyDev, pUrbLnx);
         }
         else
diff --git a/src/VBox/Devices/build/VBoxDD.cpp b/src/VBox/Devices/build/VBoxDD.cpp
index 3173a36..f7023ff 100644
--- a/src/VBox/Devices/build/VBoxDD.cpp
+++ b/src/VBox/Devices/build/VBoxDD.cpp
@@ -80,11 +80,9 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceHPET);
     if (RT_FAILURE(rc))
         return rc;
-#ifdef VBOX_WITH_SMC_NEW
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSmc);
     if (RT_FAILURE(rc))
         return rc;
-#endif
 #ifdef VBOX_WITH_EFI
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceEFI);
     if (RT_FAILURE(rc))
diff --git a/src/VBox/Devices/build/VBoxDD2.cpp b/src/VBox/Devices/build/VBoxDD2.cpp
index cdff317..8946b77 100644
--- a/src/VBox/Devices/build/VBoxDD2.cpp
+++ b/src/VBox/Devices/build/VBoxDD2.cpp
@@ -64,11 +64,6 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceIOAPIC);
     if (RT_FAILURE(rc))
         return rc;
-#ifndef VBOX_WITH_SMC_NEW
-    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSMC);
-    if (RT_FAILURE(rc))
-        return rc;
-#endif
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceLPC);
     if (RT_FAILURE(rc))
         return rc;
diff --git a/src/VBox/Devices/build/VBoxDD2.h b/src/VBox/Devices/build/VBoxDD2.h
index 4cc62bc..80000f4 100644
--- a/src/VBox/Devices/build/VBoxDD2.h
+++ b/src/VBox/Devices/build/VBoxDD2.h
@@ -45,9 +45,6 @@ extern DECLIMPORT(const unsigned)       g_cbNetBiosBinary;
 #endif /* !IN_VBOXDD2 */
 extern const PDMDEVREG g_DeviceAPIC;
 extern const PDMDEVREG g_DeviceIOAPIC;
-#ifndef VBOX_WITH_SMC_NEW
-extern const PDMDEVREG g_DeviceSMC;
-#endif
 extern const PDMDEVREG g_DeviceLPC;
 
 RT_C_DECLS_END
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
index a703393..06bdfa4 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSize.cpp
@@ -65,7 +65,7 @@
 #undef LOG_GROUP
 #include "../PC/DevLPC.cpp"
 #undef LOG_GROUP
-#include "../PC/DevSMC.cpp"
+#include "../EFI/DevSmc.cpp"
 #undef LOG_GROUP
 #include "../Storage/DevATA.cpp"
 #ifdef VBOX_WITH_USB
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 4a06c2b..54b62a9 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -40,6 +40,8 @@
 #undef LOG_GROUP
 #include "../Bus/DevPciIch9.cpp"
 #undef LOG_GROUP
+#include "../EFI/DevSmc.cpp"
+#undef LOG_GROUP
 #include "../Graphics/DevVGA.cpp"
 #undef LOG_GROUP
 #include "../Input/DevPS2.cpp"
@@ -212,6 +214,23 @@ int main()
     GEN_CHECK_OFF(ICH9PCIGLOBALS, u64PciConfigMMioLength);
     GEN_CHECK_OFF(ICH9PCIGLOBALS, aPciBus);
 
+    /* EFI/DevSMC.cpp */
+    GEN_CHECK_SIZE(DEVSMC);
+    GEN_CHECK_OFF(DEVSMC, bCmd);
+    GEN_CHECK_OFF(DEVSMC, offKey);
+    GEN_CHECK_OFF(DEVSMC, offValue);
+    GEN_CHECK_OFF(DEVSMC, cKeys);
+    GEN_CHECK_OFF(DEVSMC, CurKey);
+    GEN_CHECK_OFF(DEVSMC, u);
+    GEN_CHECK_OFF(DEVSMC, u.s);
+    GEN_CHECK_OFF(DEVSMC, u.s.bState);
+    GEN_CHECK_OFF(DEVSMC, u.s.bStatusCode);
+    GEN_CHECK_OFF(DEVSMC, u.s.bStatusCode);
+    GEN_CHECK_OFF(DEVSMC, szOsk0And1);
+    GEN_CHECK_OFF(DEVSMC, bDollaryNumber);
+    GEN_CHECK_OFF(DEVSMC, bShutdownReason);
+    GEN_CHECK_OFF(DEVSMC, bNinjaActionTimerJob);
+
     /* DevVGA.cpp */
     GEN_CHECK_SIZE(VGASTATE);
     GEN_CHECK_OFF(VGASTATE, vram_ptrR3);
@@ -567,6 +586,7 @@ int main()
     GEN_CHECK_OFF(ACPIState, pPmTimerR3);
     GEN_CHECK_OFF(ACPIState, pPmTimerR0);
     GEN_CHECK_OFF(ACPIState, pPmTimerRC);
+    GEN_CHECK_OFF(ACPIState, uPmTimerVal);
     GEN_CHECK_OFF(ACPIState, gpe0_en);
     GEN_CHECK_OFF(ACPIState, gpe0_sts);
     GEN_CHECK_OFF(ACPIState, uBatteryIndex);
@@ -588,7 +608,8 @@ int main()
     GEN_CHECK_OFF(ACPIState, fCpuHotPlug);
     GEN_CHECK_OFF(ACPIState, IBase);
     GEN_CHECK_OFF(ACPIState, IACPIPort);
-    GEN_CHECK_OFF(ACPIState, pDevIns);
+    GEN_CHECK_OFF(ACPIState, pDevInsR3);
+    GEN_CHECK_OFF(ACPIState, pDevInsR0);
     GEN_CHECK_OFF(ACPIState, pDrvBase);
     GEN_CHECK_OFF(ACPIState, pDrv);
 
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
index ced18c1..11faf67 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
@@ -2359,29 +2359,35 @@ static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot
     AssertPtrReturn(ppszSourceRoot, VERR_INVALID_POINTER);
 
     char *pszNewRoot = RTStrDup(pszSource);
-    AssertPtrReturn(pszNewRoot, VERR_NO_MEMORY);
+    if (!pszNewRoot)
+        return VERR_NO_MEMORY;
 
     size_t lenRoot = strlen(pszNewRoot);
     if (   lenRoot
-        && pszNewRoot[lenRoot - 1] == '/'
-        && pszNewRoot[lenRoot - 1] == '\\'
-        && lenRoot > 1
-        && pszNewRoot[lenRoot - 2] == '/'
-        && pszNewRoot[lenRoot - 2] == '\\')
+        && (   pszNewRoot[lenRoot - 1] == '/'
+            || pszNewRoot[lenRoot - 1] == '\\')
+       )
     {
-        *ppszSourceRoot = pszNewRoot;
-        if (lenRoot > 1)
-            *ppszSourceRoot[lenRoot - 2] = '\0';
-        *ppszSourceRoot[lenRoot - 1] = '\0';
+        pszNewRoot[lenRoot - 1] = '\0';
     }
-    else
+
+    if (   lenRoot > 1
+        && (   pszNewRoot[lenRoot - 2] == '/'
+            || pszNewRoot[lenRoot - 2] == '\\')
+       )
+    {
+        pszNewRoot[lenRoot - 2] = '\0';
+    }
+
+    if (!lenRoot)
     {
         /* If there's anything (like a file name or a filter),
          * strip it! */
         RTPathStripFilename(pszNewRoot);
-        *ppszSourceRoot = pszNewRoot;
     }
 
+    *ppszSourceRoot = pszNewRoot;
+
     return VINF_SUCCESS;
 }
 
diff --git a/src/VBox/Frontends/VirtualBox/Makefile.kmk b/src/VBox/Frontends/VirtualBox/Makefile.kmk
index 490f8e3..b0828d3 100644
--- a/src/VBox/Frontends/VirtualBox/Makefile.kmk
+++ b/src/VBox/Frontends/VirtualBox/Makefile.kmk
@@ -114,7 +114,8 @@ VirtualBox_DEFS          += \
 	$(if $(VBOX_WITH_CROGL),VBOX_WITH_CROGL) \
 	$(if $(VBOX_GUI_WITH_HIDPI),VBOX_GUI_WITH_HIDPI) \
 	$(if $(VBOX_GUI_WITH_PIDFILE),VBOX_GUI_WITH_PIDFILE) \
-	$(if $(VBOX_GUI_WITH_KEYS_RESET_HANDLER),VBOX_GUI_WITH_KEYS_RESET_HANDLER)
+	$(if $(VBOX_GUI_WITH_KEYS_RESET_HANDLER),VBOX_GUI_WITH_KEYS_RESET_HANDLER) \
+	$(if $(VBOX_GUI_WITH_CUSTOMIZATIONS1),VBOX_GUI_WITH_CUSTOMIZATIONS1)
 ifdef VBOX_WITH_DEBUGGER_GUI
  VirtualBox_DEFS        += VBOX_WITH_DEBUGGER_GUI
  if "$(KBUILD_TYPE)" != "release"
diff --git a/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp b/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
index 3c7b8cb..e3cd7e3 100644
--- a/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/VBoxFBOverlay.cpp
@@ -2258,7 +2258,7 @@ int VBoxVHWAImage::vhwaSurfaceCanCreate(struct VBOXVHWACMD_SURF_CANCREATE *pCmd)
         if (pCmd->SurfInfo.PixelFormat.flags & VBOXVHWA_PF_RGB)
         {
             if (pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 32
-                    || pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 24)
+                    && pCmd->SurfInfo.PixelFormat.c.rgbBitCount != 24)
             {
                 Assert (0);
                 pCmd->u.out.ErrInfo = -1;
diff --git a/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp b/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
index 10270f5..6f7e3d7 100644
--- a/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/extensions/QIFileDialog.cpp
@@ -482,11 +482,11 @@ QString QIFileDialog::getSaveFileName (const QString &aStartWith,
 
             ofn.lStructSize = sizeof (OPENFILENAME);
             ofn.hwndOwner = topParent ? topParent->winId() : 0;
-            ofn.lpstrFilter = (TCHAR *) winFilters.isNull() ? 0 : winFilters.utf16();
+            ofn.lpstrFilter = (TCHAR *)(winFilters.isNull() ? 0 : winFilters.utf16());
             ofn.lpstrFile = buf;
             ofn.nMaxFile = sizeof (buf) - 1;
-            ofn.lpstrInitialDir = (TCHAR *) workDir.isNull() ? 0 : workDir.utf16();
-            ofn.lpstrTitle = (TCHAR *) title.isNull() ? 0 : title.utf16();
+            ofn.lpstrInitialDir = (TCHAR *)(workDir.isNull() ? 0 : workDir.utf16());
+            ofn.lpstrTitle = (TCHAR *)(title.isNull() ? 0 : title.utf16());
             ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
                          OFN_EXPLORER | OFN_ENABLEHOOK |
                          OFN_NOTESTFILECREATE | (m_fConfirmOverwrite ? OFN_OVERWRITEPROMPT : 0));
@@ -731,11 +731,11 @@ QStringList QIFileDialog::getOpenFileNames (const QString &aStartWith,
 
             ofn.lStructSize = sizeof (OPENFILENAME);
             ofn.hwndOwner = topParent ? topParent->winId() : 0;
-            ofn.lpstrFilter = (TCHAR *) winFilters.isNull() ? 0 : winFilters.utf16();
+            ofn.lpstrFilter = (TCHAR *)(winFilters.isNull() ? 0 : winFilters.utf16());
             ofn.lpstrFile = buf;
             ofn.nMaxFile = sizeof (buf) - 1;
-            ofn.lpstrInitialDir = (TCHAR *) workDir.isNull() ? 0 : workDir.utf16();
-            ofn.lpstrTitle = (TCHAR *) title.isNull() ? 0 : title.utf16();
+            ofn.lpstrInitialDir = (TCHAR *)(workDir.isNull() ? 0 : workDir.utf16());
+            ofn.lpstrTitle = (TCHAR *)(title.isNull() ? 0 : title.utf16());
             ofn.Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY |
                           OFN_EXPLORER | OFN_ENABLEHOOK |
                           OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
index 1fe2afe..a0bf7df 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
@@ -75,6 +75,9 @@ const char* UIDefs::GUI_LastGuestSizeHintWasFullscreen = "GUI/LastGuestSizeHintW
 const char* UIDefs::GUI_Fullscreen = "GUI/Fullscreen";
 const char* UIDefs::GUI_Seamless = "GUI/Seamless";
 const char* UIDefs::GUI_Scale = "GUI/Scale";
+#ifdef Q_WS_X11
+const char* UIDefs::GUI_Fullscreen_LegacyMode = "GUI/Fullscreen/LegacyMode";
+#endif /* Q_WS_X11 */
 const char* UIDefs::GUI_VirtualScreenToHostScreen = "GUI/VirtualScreenToHostScreen";
 const char* UIDefs::GUI_AutoresizeGuest = "GUI/AutoresizeGuest";
 const char* UIDefs::GUI_AutomountGuestScreens = "GUI/AutomountGuestScreens";
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
index 20b643e..fb7f330 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
@@ -144,6 +144,9 @@ namespace UIDefs
     extern const char* GUI_Fullscreen;
     extern const char* GUI_Seamless;
     extern const char* GUI_Scale;
+#ifdef Q_WS_X11
+    extern const char* GUI_Fullscreen_LegacyMode;
+#endif /* Q_WS_X11 */
     extern const char* GUI_VirtualScreenToHostScreen;
     extern const char* GUI_AutoresizeGuest;
     extern const char* GUI_AutomountGuestScreens;
@@ -234,7 +237,8 @@ enum MacOSXRelease
     MacOSXRelease_SnowLeopard,
     MacOSXRelease_Lion,
     MacOSXRelease_MountainLion,
-    MacOSXRelease_Mavericks
+    MacOSXRelease_Mavericks,
+    MacOSXRelease_Yosemite
 };
 #endif /* Q_WS_MAC */
 
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
index a3474e8..f622362 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
@@ -330,6 +330,9 @@ MacOSXRelease VBoxGlobal::osRelease()
     if (uname(&info) != -1)
     {
         /* Parse known .release types: */
+            if (QString(info.release).startsWith("14."))
+                return MacOSXRelease_Yosemite;
+        else
             if (QString(info.release).startsWith("13."))
                 return MacOSXRelease_Mavericks;
         else
@@ -639,130 +642,6 @@ QList<ulong> XGetStrut(Window window)
 }
 #endif /* ifdef Q_WS_X11 */
 
-const QRect VBoxGlobal::availableGeometry(int iScreen) const
-{
-    /* Prepare empty result: */
-    QRect result;
-
-#ifdef Q_WS_X11
-
-    /* Get current display: */
-    Display* pDisplay = QX11Info::display();
-
-    /* Get current application desktop: */
-    QDesktopWidget *pDesktopWidget = QApplication::desktop();
-
-    /* If it's a virtual desktop: */
-    if (pDesktopWidget->isVirtualDesktop())
-    {
-        /* If it's a Xinerama desktop: */
-        if (XineramaIsActive(pDisplay))
-        {
-            /* Get desktops list: */
-            QList<QRect> desktops = XGetDesktopList();
-
-            /* Combine to get full virtual region: */
-            QRegion virtualRegion;
-            foreach (QRect desktop, desktops)
-                virtualRegion += desktop;
-            virtualRegion = virtualRegion.boundingRect();
-
-            /* Remember initial virtual desktop: */
-            QRect virtualDesktop = virtualRegion.boundingRect();
-            //AssertMsgFailed(("LOG... Virtual desktop is: %dx%dx%dx%d\n", virtualDesktop.x(), virtualDesktop.y(),
-            //                                                             virtualDesktop.width(), virtualDesktop.height()));
-
-            /* Set available geometry to screen geometry initially: */
-            result = desktops[iScreen];
-
-            /* Feat available geometry of virtual desktop to respect all the struts: */
-            QList<Window> list = XGetWindowIDList();
-            for (int i = 0; i < list.size(); ++ i)
-            {
-                /* Get window: */
-                Window wid = list[i];
-                QList<ulong> struts = XGetStrut(wid);
-
-                /* If window has strut: */
-                if (struts.size())
-                {
-                    ulong uLeftShift = struts[0];
-                    ulong uLeftFromY = struts[4];
-                    ulong uLeftToY = struts[5];
-
-                    ulong uRightShift = struts[1];
-                    ulong uRightFromY = struts[6];
-                    ulong uRightToY = struts[7];
-
-                    ulong uTopShift = struts[2];
-                    ulong uTopFromX = struts[8];
-                    ulong uTopToX = struts[9];
-
-                    ulong uBottomShift = struts[3];
-                    ulong uBottomFromX = struts[10];
-                    ulong uBottomToX = struts[11];
-
-                    if (uLeftShift)
-                    {
-                        QRect sr(QPoint(0, uLeftFromY),
-                                 QSize(uLeftShift, uLeftToY - uLeftFromY + 1));
-
-                        //AssertMsgFailed(("LOG... Subtract left strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
-                        virtualRegion -= sr;
-                    }
-
-                    if (uRightShift)
-                    {
-                        QRect sr(QPoint(virtualDesktop.x() + virtualDesktop.width() - uRightShift, uRightFromY),
-                                 QSize(virtualDesktop.x() + virtualDesktop.width(), uRightToY - uRightFromY + 1));
-
-                        //AssertMsgFailed(("LOG... Subtract right strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
-                        virtualRegion -= sr;
-                    }
-
-                    if (uTopShift)
-                    {
-                        QRect sr(QPoint(uTopFromX, 0),
-                                 QSize(uTopToX - uTopFromX + 1, uTopShift));
-
-                        //AssertMsgFailed(("LOG... Subtract top strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
-                        virtualRegion -= sr;
-                    }
-
-                    if (uBottomShift)
-                    {
-                        QRect sr(QPoint(uBottomFromX, virtualDesktop.y() + virtualDesktop.height() - uBottomShift),
-                                 QSize(uBottomToX - uBottomFromX + 1, uBottomShift));
-
-                        //AssertMsgFailed(("LOG... Subtract bottom strut: top-left: %dx%d, size: %dx%d\n", sr.x(), sr.y(), sr.width(), sr.height()));
-                        virtualRegion -= sr;
-                    }
-                }
-            }
-
-            /* Get final available geometry: */
-            result = (virtualRegion & result).boundingRect();
-        }
-    }
-
-    /* If result is still NULL: */
-    if (result.isNull())
-    {
-        /* Use QT default functionality: */
-        result = pDesktopWidget->availableGeometry(iScreen);
-    }
-
-    //AssertMsgFailed(("LOG... Final geometry: %dx%dx%dx%d\n", result.x(), result.y(), result.width(), result.height()));
-
-#else /* ifdef Q_WS_X11 */
-
-    result = QApplication::desktop()->availableGeometry(iScreen);
-
-#endif /* ifndef Q_WS_X11 */
-
-    return result;
-}
-
 /**
  *  Returns the list of few guest OS types, queried from
  *  IVirtualBox corresponding to every family id.
@@ -3496,6 +3375,15 @@ bool VBoxGlobal::shouldWeAllowApplicationUpdate(CVirtualBox &vbox)
 }
 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
 
+#ifdef Q_WS_X11
+/* static */
+bool VBoxGlobal::legacyFullscreenModeRequested(CVirtualBox vbox)
+{
+    /* 'False' unless feature requested through the extra-data: */
+    return isApprovedByExtraData(vbox, GUI_Fullscreen_LegacyMode);
+}
+#endif /* Q_WS_X11 */
+
 /* static */
 bool VBoxGlobal::shouldWeShowMachine(CMachine &machine)
 {
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
index 450ddf8..25d36cd 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
@@ -128,8 +128,6 @@ public:
     const char *vmRenderModeStr() const { return vm_render_mode_str; }
     bool isKWinManaged() const { return mIsKWinManaged; }
 
-    const QRect availableGeometry(int iScreen = 0) const;
-
     bool shouldRestoreCurrentSnapshot() const { return mRestoreCurrentSnapshot; }
     bool isPatmDisabled() const { return mDisablePatm; }
     bool isCsamDisabled() const { return mDisableCsam; }
@@ -360,6 +358,9 @@ public:
 #ifdef VBOX_GUI_WITH_NETWORK_MANAGER
     static bool shouldWeAllowApplicationUpdate(CVirtualBox &vbox);
 #endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
+#ifdef Q_WS_X11
+    static bool legacyFullscreenModeRequested(CVirtualBox vbox);
+#endif /* Q_WS_X11 */
     static bool shouldWeShowMachine(CMachine &machine);
     static bool shouldWeAllowMachineReconfiguration(CMachine &machine,
                                                     bool fIncludingMachineGeneralCheck = false,
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
index 553662b..c75eae6 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin-cocoa.mm
@@ -208,6 +208,12 @@ bool darwinIsInFullscreenMode(NativeNSWindowRef pWindow)
     return [pWindow styleMask] & NSFullScreenWindowMask;
 }
 
+bool darwinIsOnActiveSpace(NativeNSWindowRef pWindow)
+{
+    /* Check whether passed pWindow is on active space. */
+    return [pWindow isOnActiveSpace];
+}
+
 bool darwinScreensHaveSeparateSpaces()
 {
     /* Check whether screens have separate spaces.
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
index 3967cba..615ad92 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.cpp
@@ -158,6 +158,11 @@ bool darwinIsInFullscreenMode(QWidget *pWidget)
     return ::darwinIsInFullscreenMode(::darwinToNativeWindow(pWidget));
 }
 
+bool darwinIsOnActiveSpace(QWidget *pWidget)
+{
+    return ::darwinIsOnActiveSpace(::darwinToNativeWindow(pWidget));
+}
+
 void darwinInstallResizeDelegate(QWidget *pWidget)
 {
     ::darwinInstallResizeDelegate(::darwinToNativeWindow(pWidget));
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
index d9f2878..8bbda94 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/VBoxUtils-darwin.h
@@ -82,6 +82,7 @@ void darwinEnableFullscreenSupport(NativeNSWindowRef pWindow);
 void darwinEnableTransienceSupport(NativeNSWindowRef pWindow);
 void darwinToggleFullscreenMode(NativeNSWindowRef pWindow);
 bool darwinIsInFullscreenMode(NativeNSWindowRef pWindow);
+bool darwinIsOnActiveSpace(NativeNSWindowRef pWindow);
 bool darwinScreensHaveSeparateSpaces();
 
 bool darwinOpenFile(NativeNSStringRef pstrFile);
@@ -250,6 +251,7 @@ void darwinEnableFullscreenSupport(QWidget *pWidget);
 void darwinEnableTransienceSupport(QWidget *pWidget);
 void darwinToggleFullscreenMode(QWidget *pWidget);
 bool darwinIsInFullscreenMode(QWidget *pWidget);
+bool darwinIsOnActiveSpace(QWidget *pWidget);
 bool darwinOpenFile(const QString &strFile);
 
 double darwinBackingScaleFactor(QWidget *pWidget);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
index ef4c02f..b9120c3 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
@@ -291,11 +291,12 @@ UIMachineWindow* UIMachineLogic::activeMachineWindow() const
     return mainMachineWindow();
 }
 
-/** Adjusts guest screen size for each the machine-window we have. */
-void UIMachineLogic::maybeAdjustGuestScreenSize()
+void UIMachineLogic::adjustMachineWindowsGeometry()
 {
+    /* By default, the only thing we need is to
+     * adjust machine-view size(s) if necessary: */
     foreach(UIMachineWindow *pMachineWindow, machineWindows())
-        pMachineWindow->machineView()->maybeAdjustGuestScreenSize();
+        pMachineWindow->adjustMachineViewSize();
 }
 
 #ifdef Q_WS_MAC
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
index d5637b8..6e03fa3 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
@@ -80,8 +80,8 @@ public:
     bool isPreventAutoClose() const { return m_fIsPreventAutoClose; }
     void setPreventAutoClose(bool fIsPreventAutoClose) { m_fIsPreventAutoClose = fIsPreventAutoClose; }
 
-    /* API: Guest screen size stuff: */
-    virtual void maybeAdjustGuestScreenSize();
+    /** Adjusts machine-window(s) geometry if necessary. */
+    virtual void adjustMachineWindowsGeometry();
 
     /* Wrapper to open Machine settings / Network page: */
     void openNetworkAdaptersDialog() { sltOpenNetworkAdaptersDialog(); }
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
index 0404e97..f3385fc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
@@ -75,9 +75,9 @@ public:
     /* Public setters: */
     virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {}
 
-    /** Adjusts guest screen size to correspond current machine-window size.
+    /** Adjusts guest-screen size to correspond current visual-style.
       * @note Reimplemented in sub-classes. Base implementation does nothing. */
-    virtual void maybeAdjustGuestScreenSize() {}
+    virtual void adjustGuestScreenSize() {}
 
     /* Framebuffer aspect ratio: */
     double aspectRatio() const;
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
index be5048c..ce28562 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
@@ -203,6 +203,13 @@ CMachine UIMachineWindow::machine() const
     return session().GetMachine();
 }
 
+void UIMachineWindow::adjustMachineViewSize()
+{
+    /* By default, the only thing we need is to
+     * adjust guest-screen size if necessary: */
+    machineView()->adjustGuestScreenSize();
+}
+
 #ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
 void UIMachineWindow::setMask(const QRegion &region)
 {
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
index 37c0cb2..dffc9ea 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.h
@@ -62,11 +62,14 @@ public:
     CSession& session() const;
     CMachine machine() const;
 
-    /** Adjusts machine-window size to correspond current guest screen size.
+    /** Adjusts machine-window size to correspond current machine-view size.
       * @param fAdjustPosition determines whether is it necessary to adjust position too.
       * @note  Reimplemented in sub-classes. Base implementation does nothing. */
     virtual void normalizeGeometry(bool fAdjustPosition) { Q_UNUSED(fAdjustPosition); }
 
+    /** Adjusts machine-view size to correspond current machine-window size. */
+    virtual void adjustMachineViewSize();
+
 #ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
     /* Virtual caller for base class setMask: */
     virtual void setMask(const QRegion &region);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
index 0bbe1fe..06785c4 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp
@@ -276,8 +276,8 @@ void UISession::powerUp()
     if (isSaved())
     {
         msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_state_restore_90px.png", 0, 0);
-        /* After restoring from 'saved' state, guest screen size should be adjusted: */
-        machineLogic()->maybeAdjustGuestScreenSize();
+        /* After restoring from 'saved' state, machine-window(s) geometry should be adjusted: */
+        machineLogic()->adjustMachineWindowsGeometry();
     }
     else
         msgCenter().showModalProgressDialog(progress, machine.GetName(), ":/progress_start_90px.png");
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
index 6066a12..355f7bf 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
@@ -83,10 +83,9 @@ bool UIMachineLogicFullscreen::checkAvailability()
     return true;
 }
 
-/** Adjusts guest screen count/size for the machine-logic we have. */
-void UIMachineLogicFullscreen::maybeAdjustGuestScreenSize()
+void UIMachineLogicFullscreen::adjustMachineWindowsGeometry()
 {
-    LogRel(("UIMachineLogicFullscreen::maybeAdjustGuestScreenSize"));
+    LogRel(("UIMachineLogicFullscreen::adjustMachineWindowsGeometry\n"));
 
     /* Rebuild multi-screen layout: */
     m_pScreenLayout->rebuild();
@@ -99,7 +98,7 @@ void UIMachineLogicFullscreen::maybeAdjustGuestScreenSize()
         foreach (UIMachineWindow *pMachineWindow, machineWindows())
             pMachineWindow->showInNecessaryMode();
     }
-    /* Revalidate native fullscreen for ML and next: */
+    /* For ML and next revalidate native fullscreen: */
     else revalidateNativeFullScreen();
 #else /* !Q_WS_MAC */
     /* Make sure all machine-window(s) have proper geometry: */
@@ -360,14 +359,14 @@ void UIMachineLogicFullscreen::sltMachineStateChanged()
     /* If machine-state changed from 'paused' to 'running': */
     if (uisession()->isRunning() && uisession()->wasPaused())
     {
-        LogRelFlow(("UIMachineLogicFullscreen: "
-                    "Machine-state changed from 'paused' to 'running': "
-                    "Updating screen-layout...\n"));
+        LogRel(("UIMachineLogicFullscreen::sltMachineStateChanged:"
+                "Machine-state changed from 'paused' to 'running': "
+                "Adjust machine-window geometry...\n"));
 
         /* Make sure further code will be called just once: */
         uisession()->forgetPreviousMachineState();
-        /* Adjust guest-screen size if necessary: */
-        maybeAdjustGuestScreenSize();
+        /* Adjust machine-window geometry if necessary: */
+        adjustMachineWindowsGeometry();
     }
 }
 
@@ -501,6 +500,8 @@ void UIMachineLogicFullscreen::prepareMachineWindows()
         /* Register to native notifications: */
         UICocoaApplication::instance()->registerToNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this,
                                                                           UIMachineLogicFullscreen::nativeHandlerForApplicationActivation);
+        UICocoaApplication::instance()->registerToNotificationOfWorkspace("NSWorkspaceActiveSpaceDidChangeNotification", this,
+                                                                          UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange);
     }
 
     /* We have to make sure that we are getting the front most process.
@@ -589,6 +590,7 @@ void UIMachineLogicFullscreen::cleanupMachineWindows()
     {
         /* Unregister from native notifications: */
         UICocoaApplication::instance()->unregisterFromNotificationOfWorkspace("NSWorkspaceDidActivateApplicationNotification", this);
+        UICocoaApplication::instance()->unregisterFromNotificationOfWorkspace("NSWorkspaceActiveSpaceDidChangeNotification", this);
     }
 
     /* For Lion and previous fade to black: */
@@ -707,12 +709,16 @@ void UIMachineLogicFullscreen::fadeToNormal()
 
 void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMachineWindow)
 {
+    /* Make sure that is full-screen machine-window: */
+    UIMachineWindowFullscreen *pMachineWindowFullscreen = qobject_cast<UIMachineWindowFullscreen*>(pMachineWindow);
+    AssertPtrReturnVoid(pMachineWindowFullscreen);
+
     /* Make sure window is not already invalidated: */
     if (m_invalidFullscreenMachineWindows.contains(pMachineWindow))
         return;
 
     /* Ignore window if it is in 'fullscreen transition': */
-    if (qobject_cast<UIMachineWindowFullscreen*>(pMachineWindow)->isInFullscreenTransition())
+    if (pMachineWindowFullscreen->isInFullscreenTransition())
         return;
 
     /* Get screen ID: */
@@ -724,14 +730,17 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
     if (uScreenID != 0 && !screensHaveSeparateSpaces())
     {
         /* We are hiding transient window if:
-         * 1. application is inactive at all or
+         * 1. primary window is not on active user-space
          * 2. there is no fullscreen window or it's invalidated. */
-        if (   !UICocoaApplication::instance()->isActive()
+        if (   !darwinIsOnActiveSpace(machineWindows().first())
             || m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
         {
             LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
                     "Ask transient machine-window #%d to hide.\n", (int)uScreenID));
 
+            /* Make sure mini-toolbar hidden: */
+            pMachineWindowFullscreen->setMiniToolbarVisible(false);
+            /* Make sure window hidden: */
             pMachineWindow->hide();
         }
         /* If there is valid fullscreen window: */
@@ -742,6 +751,8 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
 
             /* Make sure window have proper geometry and shown: */
             pMachineWindow->showInNecessaryMode();
+            /* Make sure mini-toolbar shown: */
+            pMachineWindowFullscreen->setMiniToolbarVisible(true);
         }
     }
     /* Validate window which can be fullscreen: */
@@ -765,6 +776,8 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
                 /* Update 'presentation mode': */
                 setPresentationModeEnabled(true);
 
+                /* Make sure mini-toolbar hidden: */
+                pMachineWindowFullscreen->setMiniToolbarVisible(false);
                 /* Make sure window have proper geometry and shown: */
                 pMachineWindow->showInNecessaryMode();
 
@@ -778,6 +791,9 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
                 LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
                         "Ask machine-window #%d to hide.\n", (int)uScreenID));
 
+                /* Make sure mini-toolbar hidden: */
+                pMachineWindowFullscreen->setMiniToolbarVisible(false);
+                /* Make sure window hidden: */
                 pMachineWindow->hide();
 
                 /* Fade to normal: */
@@ -810,8 +826,11 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
                 /* Mark window as invalidated: */
                 m_invalidFullscreenMachineWindows << pMachineWindow;
 
+                /* Make sure mini-toolbar hidden: */
+                pMachineWindowFullscreen->setMiniToolbarVisible(false);
                 /* Ask window to exit 'fullscreen' mode: */
                 emit sigNotifyAboutNativeFullscreenShouldBeExited(pMachineWindow);
+                return;
             }
 
             /* If that window
@@ -821,9 +840,15 @@ void UIMachineLogicFullscreen::revalidateNativeFullScreen(UIMachineWindow *pMach
                 LogRel(("UIMachineLogicFullscreen::revalidateNativeFullScreen: "
                         "Ask machine-window #%d to adjust guest geometry.\n", (int)uScreenID));
 
-                /* Adjust guest screen size if necessary: */
-                pMachineWindow->machineView()->maybeAdjustGuestScreenSize();
+                /* Make sure mini-toolbar shown: */
+                pMachineWindowFullscreen->setMiniToolbarVisible(true);
+                /* Just adjust machine-view size if necessary: */
+                pMachineWindow->adjustMachineViewSize();
+                return;
             }
+
+            /* Make sure mini-toolbar shown: */
+            pMachineWindowFullscreen->setMiniToolbarVisible(true);
         }
     }
 }
@@ -851,36 +876,60 @@ void UIMachineLogicFullscreen::nativeHandlerForApplicationActivation(const QMap<
 {
     /* Make sure we have BundleIdentifier key: */
     AssertReturnVoid(userInfo.contains("BundleIdentifier"));
+    /* Skip other applications: */
+    QStringList ourBundleIdentifiers;
+    ourBundleIdentifiers << "org.virtualbox.app.VirtualBox";
+    ourBundleIdentifiers << "org.virtualbox.app.VirtualBoxVM";
+    ourBundleIdentifiers << "com.citrix.DesktopPlayerVM";
+    if (!ourBundleIdentifiers.contains(userInfo.value("BundleIdentifier")))
+        return;
 
-    /* On VirtualBox activation: */
-    if (userInfo.value("BundleIdentifier") == "org.virtualbox.app.VirtualBox")
-    {
-        LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: BundleIdentifier = %s\n",
-                userInfo.value("BundleIdentifier").toAscii().constData()));
+    /* Skip if 'screen have separate spaces': */
+    if (screensHaveSeparateSpaces())
+        return;
 
-        /* Make sure all the transient machine-windows updated: */
-        foreach (UIMachineWindow *pMachineWindow, machineWindows())
-            if (pMachineWindow->screenId() != 0 && !screensHaveSeparateSpaces())
-            {
-                /* If there is no fullscreen window or it's invalidated: */
-                if (m_fullscreenMachineWindows.isEmpty() || !m_invalidFullscreenMachineWindows.isEmpty())
-                {
-                    LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
-                            "Ask transient machine-window #%d to hide.\n", (int)pMachineWindow->screenId()));
-
-                    pMachineWindow->hide();
-                }
-                /* If there is valid fullscreen window: */
-                else
-                {
-                    LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
-                            "Ask transient machine-window #%d to show/normalize.\n", (int)pMachineWindow->screenId()));
+    /* Skip if there is another than needed user-space is active: */
+    if (!darwinIsOnActiveSpace(machineWindows().first()))
+        return;
 
-                    /* Make sure window have proper geometry and shown: */
-                    pMachineWindow->showInNecessaryMode();
-                }
-            }
+    LogRel(("UIMachineLogicFullscreen::nativeHandlerForApplicationActivation: "
+            "Full-screen application activated.\n"));
+
+    /* Revalidate full-screen mode for transient machine-window(s): */
+    foreach (UIMachineWindow *pMachineWindow, machineWindows())
+        if (pMachineWindow->screenId() > 0)
+            revalidateNativeFullScreen(pMachineWindow);
+}
+
+/* static */
+void UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange(QObject *pObject, const QMap<QString, QString> &userInfo)
+{
+    /* Handle arrived notification: */
+    UIMachineLogicFullscreen *pLogic = qobject_cast<UIMachineLogicFullscreen*>(pObject);
+    AssertPtrReturnVoid(pLogic);
+    {
+        /* Redirect arrived notification: */
+        pLogic->nativeHandlerForActiveSpaceChange(userInfo);
     }
 }
+
+void UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange(const QMap<QString, QString>&)
+{
+    /* Skip if 'screen have separate spaces': */
+    if (screensHaveSeparateSpaces())
+        return;
+
+    /* Skip if there is another than needed user-space is active: */
+    if (!darwinIsOnActiveSpace(machineWindows().first()))
+        return;
+
+    LogRel(("UIMachineLogicFullscreen::nativeHandlerForActiveSpaceChange: "
+            "Full-screen user-space activated.\n"));
+
+    /* Revalidate full-screen mode for transient machine-window(s): */
+    foreach (UIMachineWindow *pMachineWindow, machineWindows())
+        if (pMachineWindow->screenId() > 0)
+            revalidateNativeFullScreen(pMachineWindow);
+}
 #endif /* Q_WS_MAC */
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
index 980ba32..2d63a95 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.h
@@ -61,8 +61,10 @@ protected:
     /** Returns machine-window flags for 'Fullscreen' machine-logic and passed @a uScreenId. */
     virtual Qt::WindowFlags windowFlags(ulong uScreenId) const { Q_UNUSED(uScreenId); return Qt::FramelessWindowHint; }
 
+    /** Adjusts machine-window geometry if necessary for 'Fullscreen'. */
+    virtual void adjustMachineWindowsGeometry();
+
     /* Helpers: Multi-screen stuff: */
-    void maybeAdjustGuestScreenSize();
     int hostScreenForGuestScreen(int iScreenId) const;
     bool hasHostScreenForGuestScreen(int iScreenId) const;
 
@@ -141,10 +143,15 @@ private:
     /** Mac OS X: Revalidates 'fullscreen' mode for all windows. */
     void revalidateNativeFullScreen();
 
-    /** Mac OS X: Proxies native notification about active space change. */
+    /** Mac OS X: Proxies native notification about application activation. */
     static void nativeHandlerForApplicationActivation(QObject *pObject, const QMap<QString, QString> &userInfo);
-    /** Mac OS X: Handles native notification about active space change. */
+    /** Mac OS X: Handles native notification about application activation. */
     void nativeHandlerForApplicationActivation(const QMap<QString, QString> &userInfo);
+
+    /** Mac OS X: Proxies native notification about active space change. */
+    static void nativeHandlerForActiveSpaceChange(QObject *pObject, const QMap<QString, QString> &userInfo);
+    /** Mac OS X: Handles native notification about active space change. */
+    void nativeHandlerForActiveSpaceChange(const QMap<QString, QString> &userInfo);
 #endif /* Q_WS_MAC */
 
     /* Variables: */
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
index 6cfa25d..5bad43c 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
@@ -62,7 +62,7 @@ UIMachineViewFullscreen::~UIMachineViewFullscreen()
 
 void UIMachineViewFullscreen::sltAdditionsStateChanged()
 {
-    maybeAdjustGuestScreenSize();
+    adjustGuestScreenSize();
 }
 
 bool UIMachineViewFullscreen::eventFilter(QObject *pWatched, QEvent *pEvent)
@@ -135,10 +135,9 @@ void UIMachineViewFullscreen::setGuestAutoresizeEnabled(bool fEnabled)
     }
 }
 
-/** Adjusts guest screen size to correspond current <i>working area</i> size. */
-void UIMachineViewFullscreen::maybeAdjustGuestScreenSize()
+void UIMachineViewFullscreen::adjustGuestScreenSize()
 {
-    /* Check if we should adjust guest to new size: */
+    /* Check if we should adjust guest-screen to new size: */
     if (frameBuffer()->isAutoEnabled() ||
         (int)frameBuffer()->width() != workingArea().size().width() ||
         (int)frameBuffer()->height() != workingArea().size().height())
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
index 1b35322..ff12727 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.h
@@ -61,8 +61,10 @@ private:
     /* Private setters: */
     void setGuestAutoresizeEnabled(bool bEnabled);
 
+    /** Adjusts guest-screen size to correspond current <i>working area</i> size. */
+    void adjustGuestScreenSize();
+
     /* Helpers: Geometry stuff: */
-    void maybeAdjustGuestScreenSize();
     QRect workingArea() const;
     QSize calculateMaxGuestSize() const;
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
index c9f7f07..c1a5630 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.cpp
@@ -102,6 +102,15 @@ void UIMachineWindowFullscreen::handleNativeNotification(const QString &strNativ
         emit sigNotifyAboutNativeFullscreenFailToEnter();
     }
 }
+
+void UIMachineWindowFullscreen::setMiniToolbarVisible(bool fVisible)
+{
+    /* Make sure mini-toolbar exists: */
+    if (!m_pMiniToolBar)
+        return;
+    /* Set mini-toolbar visibility to passed one: */
+    m_pMiniToolBar->setVisible(fVisible);
+}
 #endif /* Q_WS_MAC */
 
 void UIMachineWindowFullscreen::sltMachineStateChanged()
@@ -183,8 +192,13 @@ void UIMachineWindowFullscreen::sltRevokeFocus()
     if (!isVisible())
         return;
 
+#ifndef RT_OS_DARWIN
     /* Revoke stolen focus: */
     m_pMachineView->setFocus();
+#else /* RT_OS_DARWIN */
+    /* Revoke stolen activation: */
+    activateWindow();
+#endif /* RT_OS_DARWIN */
 }
 
 void UIMachineWindowFullscreen::prepareMenu()
@@ -268,6 +282,10 @@ void UIMachineWindowFullscreen::prepareMiniToolbar()
     for (int i=0; i < actions.size(); ++i)
         menus << actions.at(i)->menu();
     m_pMiniToolBar->addMenus(menus);
+#ifdef RT_OS_DARWIN
+    connect(machineLogic(), SIGNAL(sigNotifyAbout3DOverlayVisibilityChange(bool)),
+            m_pMiniToolBar, SLOT(sltHandle3DOverlayVisibilityChange(bool)));
+#endif /* RT_OS_DARWIN */
 #ifndef RT_OS_DARWIN
     connect(m_pMiniToolBar, SIGNAL(sigMinimizeAction()), this, SLOT(showMinimized()));
 #endif /* !RT_OS_DARWIN */
@@ -275,7 +293,8 @@ void UIMachineWindowFullscreen::prepareMiniToolbar()
             gActionPool->action(UIActionIndexRuntime_Toggle_Fullscreen), SLOT(trigger()));
     connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
             gActionPool->action(UIActionIndexRuntime_Simple_Close), SLOT(trigger()));
-    connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()), this, SLOT(sltRevokeFocus()));
+    connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()),
+            this, SLOT(sltRevokeFocus()), Qt::QueuedConnection);
 }
 
 void UIMachineWindowFullscreen::cleanupMiniToolbar()
@@ -369,12 +388,21 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
     UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
     AssertPtrReturnVoid(pFullscreenLogic);
 
+#ifdef Q_WS_MAC
+    /* ML and next using native stuff: */
+    const bool fSupportsNativeFullScreen = vboxGlobal().osRelease() > MacOSXRelease_Lion;
+#endif /* Q_WS_MAC */
+
     /* Make sure this window should be shown and mapped to some host-screen: */
     if (!uisession()->isScreenVisible(m_uScreenId) ||
         !pFullscreenLogic->hasHostScreenForGuestScreen(m_uScreenId))
     {
         /* Hide mini-toolbar: */
-        if (m_pMiniToolBar)
+        if (   m_pMiniToolBar
+#ifdef Q_WS_MAC
+            && !fSupportsNativeFullScreen
+#endif /* Q_WS_MAC */
+            )
             m_pMiniToolBar->hide();
         /* Hide window: */
         hide();
@@ -385,14 +413,12 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
     if (isMinimized())
         return;
 
-    /* Which host-screen should that machine-window located on? */
-    const int iHostScreen = pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId);
-
 #ifdef Q_WS_X11
     /* On X11 calling placeOnScreen() is only needed for legacy window managers
      * which we do not test, so this is 'best effort' code. With window managers which
      * support the _NET_WM_FULLSCREEN_MONITORS protocol this would interfere unreliable. */
-    const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11();
+    const bool fSupportsNativeFullScreen = VBoxGlobal::supportsFullScreenMonitorsProtocolX11() &&
+                                           !VBoxGlobal::legacyFullscreenModeRequested(vboxGlobal().virtualBox());
     if (!fSupportsNativeFullScreen)
         placeOnScreen();
 #else /* !Q_WS_X11 */
@@ -403,7 +429,6 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
 #ifdef Q_WS_MAC
     /* ML and next using native stuff, so we can call for simple show(),
      * Lion and previous using Qt stuff, so we should call for showFullScreen(): */
-    const bool fSupportsNativeFullScreen = vboxGlobal().osRelease() > MacOSXRelease_Lion;
     if (fSupportsNativeFullScreen)
         show();
     else
@@ -419,7 +444,7 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
         /* Tell recent window managers which screen this window should be mapped to.
          * Apparently some window managers will not respond to requests for
          * unmapped windows, so do this *after* the call to showFullScreen(). */
-        VBoxGlobal::setFullScreenMonitorX11(this, iHostScreen);
+        VBoxGlobal::setFullScreenMonitorX11(this, pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId));
     }
     else
     {
@@ -430,13 +455,34 @@ void UIMachineWindowFullscreen::showInNecessaryMode()
     }
 #endif /* Q_WS_X11 */
 
-    /* Adjust guest-screen size if necessary: */
-    machineView()->maybeAdjustGuestScreenSize();
+    /* Adjust machine-view size if necessary: */
+    adjustMachineViewSize();
 
-    /* Show/Move mini-toolbar into appropriate place: */
+    /* Show mini-toolbar: */
+    if (   m_pMiniToolBar
+#ifdef Q_WS_MAC
+        && !fSupportsNativeFullScreen
+#endif /* Q_WS_MAC */
+        )
+        m_pMiniToolBar->show();
+}
+
+void UIMachineWindowFullscreen::adjustMachineViewSize()
+{
+    /* Call to base-class: */
+    UIMachineWindow::adjustMachineViewSize();
+
+    /* If mini-toolbar present: */
     if (m_pMiniToolBar)
     {
-        m_pMiniToolBar->show();
+        /* Make sure this window has fullscreen logic: */
+        UIMachineLogicFullscreen *pFullscreenLogic = qobject_cast<UIMachineLogicFullscreen*>(machineLogic());
+        AssertPtrReturnVoid(pFullscreenLogic);
+
+        /* Which host-screen should that machine-window located on? */
+        const int iHostScreen = pFullscreenLogic->hostScreenForGuestScreen(m_uScreenId);
+
+        /* Move mini-toolbar into appropriate place: */
         m_pMiniToolBar->adjustGeometry(iHostScreen);
     }
 }
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
index 7584217..87e7336 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineWindowFullscreen.h
@@ -54,6 +54,8 @@ protected:
     void handleNativeNotification(const QString &strNativeNotificationName);
     /** Mac OS X: Returns whether window is in 'fullscreen' transition. */
     bool isInFullscreenTransition() const { return m_fIsInFullscreenTransition; }
+    /** Mac OS X: Defines whether mini-toolbar should be @a fVisible. */
+    void setMiniToolbarVisible(bool fVisible);
 #endif /* Q_WS_MAC */
 
 private slots:
@@ -90,6 +92,9 @@ private:
     void placeOnScreen();
     void showInNecessaryMode();
 
+    /** Adjusts machine-view size to correspond current machine-window size. */
+    virtual void adjustMachineViewSize();
+
     /* Update stuff: */
     void updateAppearanceOf(int iElement);
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
index dd0419a..016e5e8 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
@@ -63,7 +63,7 @@ UIMachineViewNormal::~UIMachineViewNormal()
 
 void UIMachineViewNormal::sltAdditionsStateChanged()
 {
-    maybeAdjustGuestScreenSize();
+    adjustGuestScreenSize();
 }
 
 bool UIMachineViewNormal::eventFilter(QObject *pWatched, QEvent *pEvent)
@@ -185,11 +185,10 @@ void UIMachineViewNormal::maybeResendSizeHint()
     }
 }
 
-/** Adjusts guest screen size to correspond current machine-window size. */
-void UIMachineViewNormal::maybeAdjustGuestScreenSize()
+void UIMachineViewNormal::adjustGuestScreenSize()
 {
-    /* Check if we should adjust guest to new size: */
-    QSize centralWidgetSize = machineWindow()->centralWidget()->size();
+    /* Check if we should adjust guest-screen to new size: */
+    const QSize centralWidgetSize = machineWindow()->centralWidget()->size();
     if ((int)frameBuffer()->width() != centralWidgetSize.width() ||
         (int)frameBuffer()->height() != centralWidgetSize.height())
         if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
index 233a19e..aa2ab61 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.h
@@ -66,8 +66,10 @@ private:
     /** Resends guest size-hint if necessary. */
     void maybeResendSizeHint();
 
+    /** Adjusts guest-screen size to correspond current <i>machine-window</i> size. */
+    void adjustGuestScreenSize();
+
     /* Private helpers: */
-    void maybeAdjustGuestScreenSize();
     QRect workingArea() const;
     QSize calculateMaxGuestSize() const;
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
index 57658a9..8ba24cc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
@@ -364,6 +364,15 @@ void UIMachineWindowNormal::prepareVisualState()
     /* Call to base-class: */
     UIMachineWindow::prepareVisualState();
 
+#ifdef VBOX_GUI_WITH_CUSTOMIZATIONS1
+    /* Customer request: The background has to go black: */
+    QPalette palette(centralWidget()->palette());
+    palette.setColor(centralWidget()->backgroundRole(), Qt::black);
+    centralWidget()->setPalette(palette);
+    centralWidget()->setAutoFillBackground(true);
+    setAutoFillBackground(true);
+#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
+
     /* Make sure host-combination LED will be updated: */
     connect(&vboxGlobal().settings(), SIGNAL(propertyChanged(const char *, const char *)),
             this, SLOT(sltProcessGlobalSettingChange(const char *, const char *)));
@@ -609,6 +618,7 @@ void UIMachineWindowNormal::showInNecessaryMode()
  */
 void UIMachineWindowNormal::normalizeGeometry(bool fAdjustPosition)
 {
+#ifndef VBOX_GUI_WITH_CUSTOMIZATIONS1
     /* Skip if maximized: */
     if (isMaximized())
         return;
@@ -640,6 +650,11 @@ void UIMachineWindowNormal::normalizeGeometry(bool fAdjustPosition)
     /* Finally, set the frame geometry: */
     setGeometry(frameGeo.left() + dl, frameGeo.top() + dt,
                 frameGeo.width() - dl - dr, frameGeo.height() - dt - db);
+#else /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
+    /* Customer request: There should no be
+     * machine-window resize on machine-view resize: */
+    Q_UNUSED(fAdjustPosition);
+#endif /* VBOX_GUI_WITH_CUSTOMIZATIONS1 */
 }
 
 void UIMachineWindowNormal::updateAppearanceOf(int iElement)
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
index de18d3b..1432951 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
@@ -76,10 +76,9 @@ bool UIMachineLogicSeamless::checkAvailability()
     return true;
 }
 
-/** Adjusts guest screen count/size for the machine-logic we have. */
-void UIMachineLogicSeamless::maybeAdjustGuestScreenSize()
+void UIMachineLogicSeamless::adjustMachineWindowsGeometry()
 {
-    LogRel(("UIMachineLogicSeamless::maybeAdjustGuestScreenSize"));
+    LogRel(("UIMachineLogicSeamless::adjustMachineWindowsGeometry\n"));
 
     /* Rebuild multi-screen layout: */
     m_pScreenLayout->rebuild();
@@ -135,14 +134,14 @@ void UIMachineLogicSeamless::sltMachineStateChanged()
     /* If machine-state changed from 'paused' to 'running': */
     if (uisession()->isRunning() && uisession()->wasPaused())
     {
-        LogRelFlow(("UIMachineLogicSeamless: "
-                    "Machine-state changed from 'paused' to 'running': "
-                    "Updating screen-layout...\n"));
+        LogRel(("UIMachineLogicSeamless::sltMachineStateChanged:"
+                "Machine-state changed from 'paused' to 'running': "
+                "Adjust machine-window geometry...\n"));
 
         /* Make sure further code will be called just once: */
         uisession()->forgetPreviousMachineState();
-        /* Adjust guest-screen size if necessary: */
-        maybeAdjustGuestScreenSize();
+        /* Adjust machine-window geometry if necessary: */
+        adjustMachineWindowsGeometry();
     }
 }
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
index e363de6..6904add 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.h
@@ -40,8 +40,10 @@ protected:
     /** Returns machine-window flags for 'Seamless' machine-logic and passed @a uScreenId. */
     virtual Qt::WindowFlags windowFlags(ulong uScreenId) const { Q_UNUSED(uScreenId); return Qt::FramelessWindowHint; }
 
+    /** Adjusts machine-window geometry if necessary for 'Seamless'. */
+    virtual void adjustMachineWindowsGeometry();
+
     /* Helpers: Multi-screen stuff: */
-    void maybeAdjustGuestScreenSize();
     int hostScreenForGuestScreen(int iScreenId) const;
     bool hasHostScreenForGuestScreen(int iScreenId) const;
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
index 4d7fffd..20a1edc 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
@@ -71,7 +71,7 @@ UIMachineViewSeamless::~UIMachineViewSeamless()
 
 void UIMachineViewSeamless::sltAdditionsStateChanged()
 {
-    maybeAdjustGuestScreenSize();
+    adjustGuestScreenSize();
 }
 
 void UIMachineViewSeamless::sltHandleSetVisibleRegion(QRegion region)
@@ -153,10 +153,9 @@ void UIMachineViewSeamless::cleanupSeamless()
         session().GetConsole().GetDisplay().SetSeamlessMode(false);
 }
 
-/** Adjusts guest screen size to correspond current <i>working area</i> size. */
-void UIMachineViewSeamless::maybeAdjustGuestScreenSize()
+void UIMachineViewSeamless::adjustGuestScreenSize()
 {
-    /* Check if we should adjust guest to new size: */
+    /* Check if we should adjust guest-screen to new size: */
     if (frameBuffer()->isAutoEnabled() ||
         (int)frameBuffer()->width() != workingArea().size().width() ||
         (int)frameBuffer()->height() != workingArea().size().height())
@@ -173,7 +172,7 @@ QRect UIMachineViewSeamless::workingArea() const
     /* Get corresponding screen: */
     int iScreen = static_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(screenId());
     /* Return available geometry for that screen: */
-    return vboxGlobal().availableGeometry(iScreen);
+    return QApplication::desktop()->availableGeometry(iScreen);
 }
 
 QSize UIMachineViewSeamless::calculateMaxGuestSize() const
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
index eda6944..c9726f6 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.h
@@ -63,8 +63,10 @@ private:
     //void cleanupFilters() {}
     //void cleanupCommon() {}
 
+    /** Adjusts guest-screen size to correspond current <i>working area</i> size. */
+    void adjustGuestScreenSize();
+
     /* Helpers: Geometry stuff: */
-    void maybeAdjustGuestScreenSize();
     QRect workingArea() const;
     QSize calculateMaxGuestSize() const;
 
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
index bf3eefc..339767a 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
@@ -80,6 +80,22 @@ void UIMachineWindowSeamless::sltRevokeFocus()
     m_pMachineView->setFocus();
 }
 
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+void UIMachineWindowSeamless::sltUpdateMiniToolbarMask(const QRect &geo)
+{
+    /* Make sure mini-toolbar exists: */
+    AssertPtrReturnVoid(m_pMiniToolBar);
+
+    /* Remember mini-toolbar mask: */
+    m_maskMiniToolbar = geo;
+
+    /* Re-assign guest mask. */
+    setMask(m_maskGuest);
+}
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
 void UIMachineWindowSeamless::prepareMenu()
 {
     /* Call to base-class: */
@@ -119,7 +135,7 @@ void UIMachineWindowSeamless::prepareVisualState()
 #else /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
     /* Make sure we have no background
      * until the first one set-region-event: */
-    setMask(m_maskRegion);
+    setMask(m_maskGuest);
 #endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
 
 #ifndef Q_WS_MAC
@@ -162,6 +178,12 @@ void UIMachineWindowSeamless::prepareMiniToolbar()
     connect(m_pMiniToolBar, SIGNAL(sigCloseAction()),
             gActionPool->action(UIActionIndexRuntime_Simple_Close), SLOT(trigger()));
     connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutFocusStolen()), this, SLOT(sltRevokeFocus()));
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+    connect(m_pMiniToolBar, SIGNAL(sigNotifyAboutGeometryChange(const QRect&)),
+            this, SLOT(sltUpdateMiniToolbarMask(const QRect&)));
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
 }
 #endif /* !Q_WS_MAC */
 
@@ -206,7 +228,7 @@ void UIMachineWindowSeamless::placeOnScreen()
     /* Get corresponding screen: */
     int iScreen = qobject_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(m_uScreenId);
     /* And corresponding working area: */
-    QRect workingArea = vboxGlobal().availableGeometry(iScreen);
+    QRect workingArea = QApplication::desktop()->availableGeometry(iScreen);
 
     /* Move to the appropriate position: */
     move(workingArea.topLeft());
@@ -245,15 +267,34 @@ void UIMachineWindowSeamless::showInNecessaryMode()
     /* Show in normal mode: */
     show();
 
-    /* Adjust guest screen size if necessary: */
-    machineView()->maybeAdjustGuestScreenSize();
+    /* Adjust machine-view size if necessary: */
+    adjustMachineViewSize();
 
 #ifndef Q_WS_MAC
-    /* Show/Move mini-toolbar into appropriate place: */
+    /* Show mini-toolbar: */
     if (m_pMiniToolBar)
-    {
         m_pMiniToolBar->show();
-        m_pMiniToolBar->adjustGeometry();
+#endif /* !Q_WS_MAC */
+}
+
+void UIMachineWindowSeamless::adjustMachineViewSize()
+{
+    /* Call to base-class: */
+    UIMachineWindow::adjustMachineViewSize();
+
+#ifndef Q_WS_MAC
+    /* If mini-toolbar present: */
+    if (m_pMiniToolBar)
+    {
+        /* Make sure this window has seamless logic: */
+        const UIMachineLogicSeamless *pSeamlessLogic = qobject_cast<UIMachineLogicSeamless*>(machineLogic());
+        AssertPtrReturnVoid(pSeamlessLogic);
+
+        /* Which host-screen should that machine-window located on? */
+        const int iHostScreen = pSeamlessLogic->hostScreenForGuestScreen(m_uScreenId);
+
+        /* Move mini-toolbar into appropriate place: */
+        m_pMiniToolBar->adjustGeometry(iHostScreen);
     }
 #endif /* !Q_WS_MAC */
 }
@@ -298,34 +339,40 @@ void UIMachineWindowSeamless::showEvent(QShowEvent*)
 #endif /* VBOX_WITH_TRANSLUCENT_SEAMLESS && Q_WS_WIN */
 
 #ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
-void UIMachineWindowSeamless::setMask(const QRegion &region)
+void UIMachineWindowSeamless::setMask(const QRegion &maskGuest)
 {
-    /* Prepare mask-region: */
-    QRegion maskRegion(region);
+    /* Remember new guest mask: */
+    m_maskGuest = maskGuest;
+
+    /* Prepare full mask: */
+    QRegion maskFull(m_maskGuest);
 
-    /* Shift region if left spacer width is NOT zero or top spacer height is NOT zero: */
+    /* Shift full mask if left or top spacer width is NOT zero: */
     if (m_pLeftSpacer->geometry().width() || m_pTopSpacer->geometry().height())
-        maskRegion.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
+        maskFull.translate(m_pLeftSpacer->geometry().width(), m_pTopSpacer->geometry().height());
 
-    /* Seamless-window for empty region should be empty too,
+# ifdef Q_WS_X11
+    /* Take into account mini-toolbar mask if necessary: */
+    if (m_pMiniToolBar)
+        maskFull += m_maskMiniToolbar;
+# endif /* Q_WS_X11 */
+
+    /* Seamless-window for empty full mask should be empty too,
      * but the QWidget::setMask() wrapper doesn't allow this.
-     * Instead, we have a full painted screen of seamless-geometry size visible.
-     * Moreover, we can't just hide the empty seamless-window as 'hiding'
-     * 1. will collide with the multi-screen layout behavior and
-     * 2. will cause a task-bar flicker on moving window from one screen to another.
-     * As a *temporary* though quite a dirty workaround we have to make sure
-     * region have at least one pixel. */
-    if (maskRegion.isEmpty())
-        maskRegion += QRect(0, 0, 1, 1);
-    /* Make sure mask-region had changed: */
-    if (m_maskRegion != maskRegion)
+     * Instead, we see a full guest-screen of available-geometry size.
+     * So we have to make sure full mask have at least one pixel. */
+    if (maskFull.isEmpty())
+        maskFull += QRect(0, 0, 1, 1);
+
+    /* Make sure full mask had changed: */
+    if (m_maskFull != maskFull)
     {
         /* Compose viewport region to update: */
-        QRegion toUpdate = m_maskRegion + maskRegion;
-        /* Remember new mask-region: */
-        m_maskRegion = maskRegion;
-        /* Assign new mask-region: */
-        UIMachineWindow::setMask(m_maskRegion);
+        QRegion toUpdate = m_maskFull + maskFull;
+        /* Remember new full mask: */
+        m_maskFull = maskFull;
+        /* Assign new full mask: */
+        UIMachineWindow::setMask(m_maskFull);
         /* Update viewport region finally: */
         m_pMachineView->viewport()->update(toUpdate);
     }
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
index a7bfea8..5e15568 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
@@ -48,6 +48,13 @@ private slots:
     /** Revokes keyboard-focus. */
     void sltRevokeFocus();
 
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+    /** Assigns mini-toolbar seamless mask. */
+    void sltUpdateMiniToolbarMask(const QRect &geo);
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
 private:
 
     /* Prepare helpers: */
@@ -68,6 +75,9 @@ private:
     void placeOnScreen();
     void showInNecessaryMode();
 
+    /** Adjusts machine-view size to correspond current machine-window size. */
+    virtual void adjustMachineViewSize();
+
 #ifndef Q_WS_MAC
     /* Update routines: */
     void updateAppearanceOf(int iElement);
@@ -79,8 +89,8 @@ private:
 #endif /* VBOX_WITH_TRANSLUCENT_SEAMLESS && Q_WS_WIN */
 
 #ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
-    /* Helper: Masking stuff: */
-    void setMask(const QRegion &region);
+    /** Assigns guest seamless mask. */
+    void setMask(const QRegion &maskGuest);
 #endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
 
     /* Widgets: */
@@ -90,8 +100,14 @@ private:
 #endif /* !Q_WS_MAC */
 
 #ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
-    /* Variable: Masking stuff: */
-    QRegion m_maskRegion;
+    /** Holds the full seamless mask. */
+    QRegion m_maskFull;
+    /** Holds the guest seamless mask. */
+    QRegion m_maskGuest;
+# ifdef Q_WS_X11
+    /** Holds the mini-toolbar seamless mask. */
+    QRect m_maskMiniToolbar;
+# endif /* Q_WS_X11 */
 #endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
 
     /* Factory support: */
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h b/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
index 28a7040..c5d9fe0 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIApplianceEditorWidget.h
@@ -53,7 +53,7 @@ class ModelItem
 public:
     ModelItem(int number, ModelItem_type type, ModelItem *pParent = NULL);
 
-    ~ModelItem();
+    virtual ~ModelItem();
 
     ModelItem *parent() const { return m_pParentItem; }
 
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
index 349f826..e008476 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
@@ -39,15 +39,20 @@
 # include "VBoxUtils-darwin.h"
 #endif /* Q_WS_MAC */
 
-#ifndef Q_WS_X11
-# define VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
-#endif /* !Q_WS_X11 */
 
 UIRuntimeMiniToolBar::UIRuntimeMiniToolBar(QWidget *pParent,
                                            GeometryType geometryType,
                                            Qt::Alignment alignment,
                                            bool fAutoHide /* = true */)
-    : QWidget(pParent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
+    : QWidget(pParent,
+#if   defined (Q_WS_WIN)
+              Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint
+#elif defined (Q_WS_MAC)
+              Qt::Window | Qt::FramelessWindowHint
+#elif defined (Q_WS_X11)
+              Qt::Widget
+#endif /* RT_OS_DARWIN */
+              )
     /* Variables: General stuff: */
     , m_geometryType(geometryType)
     , m_alignment(alignment)
@@ -138,10 +143,15 @@ void UIRuntimeMiniToolBar::adjustGeometry(int iHostScreen /* = -1 */)
     int iX = 0, iY = 0;
     switch (m_geometryType)
     {
-        case GeometryType_Available: screenRect = vboxGlobal().availableGeometry(iHostScreen); break;
+        case GeometryType_Available: screenRect = QApplication::desktop()->availableGeometry(iHostScreen); break;
         case GeometryType_Full:      screenRect = QApplication::desktop()->screenGeometry(iHostScreen); break;
         default: break;
     }
+#ifdef Q_WS_X11
+    /* Disregard origin under X11,
+     * because this is widget, not window: */
+    screenRect.moveTopLeft(QPoint(0, 0));
+#endif /* Q_WS_X11 */
     iX = screenRect.x() + screenRect.width() / 2 - width() / 2;
     switch (m_alignment)
     {
@@ -192,7 +202,12 @@ void UIRuntimeMiniToolBar::sltHoverLeave()
 
 void UIRuntimeMiniToolBar::prepare()
 {
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
+#ifdef RT_OS_DARWIN
+    /* Install own event filter: */
+    installEventFilter(this);
+#endif /* RT_OS_DARWIN */
+
+#if defined(Q_WS_MAC) || defined(Q_WS_WIN)
     /* Make sure we have no background
      * until the first one paint-event: */
     setAttribute(Qt::WA_NoSystemBackground);
@@ -208,7 +223,7 @@ void UIRuntimeMiniToolBar::prepare()
      * - Under x11 host Qt has broken XComposite support (black background): */
     setAttribute(Qt::WA_TranslucentBackground);
 # endif /* Q_WS_WIN */
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
+#endif /* Q_WS_MAC || Q_WS_WIN */
 
     /* Make sure we have no focus: */
     setFocusPolicy(Qt::NoFocus);
@@ -283,9 +298,6 @@ void UIRuntimeMiniToolBar::prepare()
 
     /* Adjust geometry finally: */
     adjustGeometry();
-
-    /* Show: */
-    show();
 }
 
 void UIRuntimeMiniToolBar::cleanup()
@@ -329,6 +341,7 @@ void UIRuntimeMiniToolBar::leaveEvent(QEvent*)
 
 bool UIRuntimeMiniToolBar::eventFilter(QObject *pWatched, QEvent *pEvent)
 {
+#ifndef RT_OS_DARWIN
     /* Due to Qt bug QMdiArea can
      * 1. steal focus from current application focus-widget
      * 3. and even request focus stealing if QMdiArea hidden yet.
@@ -336,6 +349,13 @@ bool UIRuntimeMiniToolBar::eventFilter(QObject *pWatched, QEvent *pEvent)
     if (pWatched && m_pEmbeddedToolbar && pWatched == m_pEmbeddedToolbar &&
         pEvent->type() == QEvent::FocusIn)
         emit sigNotifyAboutFocusStolen();
+#else /* RT_OS_DARWIN */
+    /* Due to Qt bug on Mac OS X window will be activated
+     * even if has Qt::WA_ShowWithoutActivating attribute. */
+    if (pWatched == this &&
+        pEvent->type() == QEvent::WindowActivate)
+        emit sigNotifyAboutFocusStolen();
+#endif /* RT_OS_DARWIN */
     /* Call to base-class: */
     return QWidget::eventFilter(pWatched, pEvent);
 }
@@ -382,6 +402,12 @@ void UIRuntimeMiniToolBar::setToolbarPosition(QPoint point)
      * Mac host has native translucency support,
      * Win host allows to enable it through Qt::WA_TranslucentBackground: */
     setMask(m_pEmbeddedToolbar->geometry());
+
+# ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+    /* Notify listeners as well: */
+    const QRect windowGeo = geometry();
+    emit sigNotifyAboutGeometryChange(windowGeo.intersected(m_pEmbeddedToolbar->geometry().translated(windowGeo.topLeft())));
+# endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
 #endif /* Q_WS_X11 */
 }
 
@@ -538,10 +564,8 @@ void UIMiniToolBar::prepare()
     /* Configure toolbar: */
     setIconSize(QSize(16, 16));
 
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
     /* Left margin: */
     m_spacings << widgetForAction(addWidget(new QWidget));
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
 
     /* Prepare push-pin: */
     m_pAutoHideAction = new QAction(this);
@@ -592,10 +616,8 @@ void UIMiniToolBar::prepare()
     connect(m_pCloseAction, SIGNAL(triggered()), this, SIGNAL(sigCloseAction()));
     addAction(m_pCloseAction);
 
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
     /* Right margin: */
     m_spacings << widgetForAction(addWidget(new QWidget));
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
 
     /* Resize to sizehint: */
     resize(sizeHint());
@@ -603,7 +625,6 @@ void UIMiniToolBar::prepare()
 
 void UIMiniToolBar::rebuildShape()
 {
-#ifdef VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR
     /* Rebuild shape: */
     QPainterPath shape;
     switch (m_alignment)
@@ -637,6 +658,5 @@ void UIMiniToolBar::rebuildShape()
 
     /* Update: */
     update();
-#endif /* VBOX_RUNTIME_UI_WITH_SHAPED_MINI_TOOLBAR */
 }
 
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
index f55183e..1bfa0bb 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
@@ -66,6 +66,13 @@ signals:
     /** Notifies listeners about we stole focus. */
     void sigNotifyAboutFocusStolen();
 
+#ifndef VBOX_WITH_TRANSLUCENT_SEAMLESS
+# ifdef Q_WS_X11
+    /** Notifies about geometry change. */
+    void sigNotifyAboutGeometryChange(const QRect &geo);
+# endif /* Q_WS_X11 */
+#endif /* !VBOX_WITH_TRANSLUCENT_SEAMLESS */
+
 public:
 
     /* Constructor/destructor: */
@@ -93,6 +100,11 @@ public:
 
 private slots:
 
+#ifdef RT_OS_DARWIN
+    /** Handle 3D overlay visibility change. */
+    void sltHandle3DOverlayVisibilityChange(bool fVisible) { if (fVisible) activateWindow(); }
+#endif /* RT_OS_DARWIN */
+
     /* Handlers: Toolbar stuff: */
     void sltHandleToolbarResize();
     void sltAutoHideToggled();
diff --git a/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp b/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
index 2144c1e..0dee59e 100644
--- a/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/wizards/exportappliance/UIWizardExportApp.cpp
@@ -186,7 +186,7 @@ QString UIWizardExportApp::uri(bool fWithFile) const
                 uri = QString("%1%2").arg(uri).arg(field("username").toString());
             if (!field("password").toString().isEmpty())
                 uri = QString("%1:%2").arg(uri).arg(field("password").toString());
-            if (!field("username").toString().isEmpty() || !field("username").toString().isEmpty())
+            if (!field("username").toString().isEmpty() || !field("password").toString().isEmpty())
                 uri = QString("%1@").arg(uri);
             uri = QString("%1%2/%3/%4").arg(uri).arg("object.storage.network.com").arg(field("bucket").toString()).arg(path);
             return uri;
diff --git a/src/VBox/HostDrivers/Support/Makefile.kmk b/src/VBox/HostDrivers/Support/Makefile.kmk
index 50f89c7..819eae5 100644
--- a/src/VBox/HostDrivers/Support/Makefile.kmk
+++ b/src/VBox/HostDrivers/Support/Makefile.kmk
@@ -222,6 +222,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
 	$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldr.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldrEx.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/ldr/ldrPE.cpp \
+	$(VBOX_PATH_RUNTIME_SRC)/common/alloc/heapsimple.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-basics.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-cursor.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/asn1/asn1-default-allocator.cpp \
@@ -324,6 +325,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrCopy.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrNCmp.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/RTStrNLen.cpp \
+	$(VBOX_PATH_RUNTIME_SRC)/common/string/RTUtf16NLenEx.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/strchr.asm \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/strcmp.asm \
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/strcpy.asm \
@@ -343,6 +345,9 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
 	$(VBOX_PATH_RUNTIME_SRC)/common/string/unidata-lower.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/common/time/time.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/generic/RTAssertShouldPanic-generic.cpp \
+	$(VBOX_PATH_RUNTIME_SRC)/generic/RTPathAbs-generic.cpp \
+	$(VBOX_PATH_RUNTIME_SRC)/generic/RTPathGetCurrentDrive-generic.cpp \
+	$(VBOX_PATH_RUNTIME_SRC)/generic/RTPathGetCurrentOnDrive-generic.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/generic/memsafer-generic.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/generic/uuid-generic.cpp \
        \
@@ -357,6 +362,7 @@ if "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING) ## @todo some of
  SUPR3HardenedStatic_SOURCES.win += \
  	win/SUPR3HardenedNoCrt-win.cpp \
  	$(VBOX_PATH_RUNTIME_SRC)/nt/RTErrConvertFromNtStatus.cpp \
+ 	$(VBOX_PATH_RUNTIME_SRC)/r3/nt/pathint-nt.cpp \
  	$(VBOX_PATH_RUNTIME_SRC)/win/RTErrConvertFromWin32.cpp \
 	$(VBOX_PATH_RUNTIME_SRC)/win/errmsgwin.cpp
 
@@ -397,6 +403,7 @@ SUPR3HardenedMain.cpp_DEFS = VBOX_SVN_REV=$(VBOX_SVN_REV)
 # VBoxSupLib - Windows DLL for catching thread creation and termination.
 #
 VBoxSupLib_TEMPLATE = $(if-expr "$(KBUILD_TARGET)" == "win" && defined(VBOX_WITH_HARDENING),VBOXR3HARDENEDLIB,VBOXR3)
+VBoxSupLib_SDKS.win = VBOX_NTDLL
 VBoxSupLib_LDFLAGS.win.amd64 = -Entry:DllMainEntrypoint
 VBoxSupLib_LDFLAGS.win.x86   = -Entry:DllMainEntrypoint
 VBoxSupLib_DEFS = \
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIOC.h b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
index c01da48..17b05a3 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvIOC.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
@@ -1,4 +1,4 @@
-/* $Revision: 94789 $ */
+/* $Revision: 96490 $ */
 /** @file
  * VirtualBox Support Driver - IOCtl definitions.
  */
@@ -61,6 +61,19 @@
 # define SUP_NT_STATUS_IS_VBOX(a_rcNt)          ( ((uint32_t)(a_rcNt) & 0xffff0000) == SUP_NT_STATUS_BASE )
 # define SUP_NT_STATUS_TO_VBOX(a_rcNt)          ( (int)((uint32_t)(a_rcNt) | UINT32_C(0xffff0000)) )
 
+/** NT device name for system access. */
+# define SUPDRV_NT_DEVICE_NAME_SYS              L"\\Device\\VBoxDrv"
+/** NT device name for user access. */
+# define SUPDRV_NT_DEVICE_NAME_USR              L"\\Device\\VBoxDrvU"
+# ifdef VBOX_WITH_HARDENING
+/** NT device name for hardened stub access. */
+#  define SUPDRV_NT_DEVICE_NAME_STUB            L"\\Device\\VBoxDrvStub"
+/** NT device name for getting error information for failed VBoxDrv or
+ * VBoxDrvStub open. */
+#  define SUPDRV_NT_DEVICE_NAME_ERROR_INFO      L"\\Device\\VBoxDrvErrorInfo"
+# endif
+
+
 #elif defined(RT_OS_SOLARIS)
   /* No automatic buffering, size limited to 255 bytes. */
 # include <sys/ioccom.h>
@@ -197,7 +210,7 @@ typedef SUPREQHDR *PSUPREQHDR;
  * @todo Pending work on next major version change:
  *          - Remove RTSpinlockReleaseNoInts.
  */
-#define SUPDRV_IOC_VERSION                              0x001a0007
+#define SUPDRV_IOC_VERSION                              0x001a0008
 
 /** SUP_IOCTL_COOKIE. */
 typedef struct SUPCOOKIE
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
index a881a44..026d478 100644
--- a/src/VBox/HostDrivers/Support/SUPLib.cpp
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -261,7 +261,8 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
     /*
      * Open the support driver.
      */
-    int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted);
+    SUPINITOP enmWhat = kSupInitOp_Driver;
+    int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted, &enmWhat, NULL);
     if (RT_SUCCESS(rc))
     {
         /*
@@ -278,7 +279,7 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
         strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
         CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
         const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x001a0000
-                                   ? 0x001a0005
+                                   ? 0x001a0008
                                    : SUPDRV_IOC_VERSION & 0xffff0000;
         CookieReq.u.In.u32MinVersion = uMinVersion;
         rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
diff --git a/src/VBox/HostDrivers/Support/SUPLibInternal.h b/src/VBox/HostDrivers/Support/SUPLibInternal.h
index 90351cf..1676d4e 100644
--- a/src/VBox/HostDrivers/Support/SUPLibInternal.h
+++ b/src/VBox/HostDrivers/Support/SUPLibInternal.h
@@ -312,11 +312,19 @@ typedef FNSUPR3PREINIT *PFNSUPR3PREINIT;
 typedef enum SUPR3HARDENEDMAINSTATE
 {
     SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED = 0,
-    SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY,
+    SUPR3HARDENEDMAINSTATE_WIN_EARLY_INIT_CALLED,
+    SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED,
+    SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED,
+    SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED,
+    SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED,
+    SUPR3HARDENEDMAINSTATE_WIN_VERSION_INITIALIZED,
+    SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY,
+    SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED,
     SUPR3HARDENEDMAINSTATE_INIT_RUNTIME,
     SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN,
     SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN,
-    SUPR3HARDENEDMAINSTATE_END
+    SUPR3HARDENEDMAINSTATE_END,
+    SUPR3HARDENEDMAINSTATE_32BIT_HACK = 0x7fffffff
 } SUPR3HARDENEDMAINSTATE;
 
 
@@ -327,6 +335,9 @@ extern DECLHIDDEN(uint32_t)     g_u32Cookie;
 extern DECLHIDDEN(uint32_t)     g_u32SessionCookie;
 extern DECLHIDDEN(SUPLIBDATA)   g_supLibData;
 extern DECLHIDDEN(SUPR3HARDENEDMAINSTATE) g_enmSupR3HardenedMainState;
+#ifdef RT_OS_WINDOWS
+extern DECLHIDDEN(bool)                 g_fSupEarlyProcessInit;
+#endif
 
 
 /*******************************************************************************
@@ -335,7 +346,7 @@ extern DECLHIDDEN(SUPR3HARDENEDMAINSTATE) g_enmSupR3HardenedMainState;
 RT_C_DECLS_BEGIN
 int     suplibOsInstall(void);
 int     suplibOsUninstall(void);
-int     suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted);
+int     suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo);
 int     suplibOsTerm(PSUPLIBDATA pThis);
 int     suplibOsHardenedVerifyInit(void);
 int     suplibOsHardenedVerifyTerm(void);
@@ -428,10 +439,17 @@ DECLHIDDEN(void)    supR3HardenedGetPreInitData(PSUPPREINITDATA pPreInitData);
 DECLHIDDEN(int)     supR3HardenedRecvPreInitData(PCSUPPREINITDATA pPreInitData);
 
 #ifdef RT_OS_WINDOWS
-DECLHIDDEN(void)    supR3HardenedWinInit(uint32_t fFlags);
+DECLHIDDEN(void)    supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge);
 DECLHIDDEN(void)    supR3HardenedWinInitVersion(void);
 DECLHIDDEN(void)    supR3HardenedWinInitImports(void);
-DECLHIDDEN(void)    supR3HardenedWinVerifyProcess(void);
+# ifdef ___iprt_nt_nt_h___
+DECLHIDDEN(void)    supR3HardenedWinGetVeryEarlyImports(uintptr_t uNtDllAddr,
+                                                        PFNNTWAITFORSINGLEOBJECT *ppfnNtWaitForSingleObject,
+                                                        PFNNTSETEVENT *ppfnNtSetEvent);
+# endif
+DECLHIDDEN(void)    supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr);
+DECLHIDDEN(void)    supR3HardenedWinInitSyscalls(bool fReportErrors);
+DECLHIDDEN(PFNRT)   supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure);
 DECLHIDDEN(void)    supR3HardenedWinEnableThreadCreation(void);
 DECLHIDDEN(void)    supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(const char *pszProgName);
 DECLHIDDEN(void)    supR3HardenedWinFlushLoaderCache();
@@ -445,6 +463,11 @@ extern RTUTF16      g_wszSupLibHardenedExePath[1024];
 # ifdef RTPATH_MAX
 extern char         g_szSupLibHardenedExePath[RTPATH_MAX];
 # endif
+DECLHIDDEN(void)    supR3HardenedWinCompactHeaps(void);
+DECLHIDDEN(void)    supR3HardenedMainOpenDevice(void);
+DECLHIDDEN(char *)  supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix);
+DECLHIDDEN(void)    supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
+                                                        const char *pszFormat, va_list va);
 #endif
 
 SUPR3DECL(int)      supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages);
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
index 017a5e2..4f4780c 100644
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
@@ -118,6 +118,10 @@ typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, uint32_t fFlags, int c
                                        char **papszArgs, const char *pszProgramPath);
 typedef FNRTR3INITEX *PFNRTR3INITEX;
 
+/** @see RTLogRelPrintf */
+typedef DECLCALLBACK(void) FNRTLOGRELPRINTF(const char *pszFormat, ...);
+typedef FNRTLOGRELPRINTF *PFNRTLOGRELPRINTF;
+
 
 /*******************************************************************************
 *   Global Variables                                                           *
@@ -153,9 +157,18 @@ static HANDLE           g_hStartupLog = NULL;
 #else
 static int              g_hStartupLog = -1;
 #endif
+/** The number of bytes we've written to the startup log. */
+static uint32_t volatile g_cbStartupLog = 0;
 
 /** The current SUPR3HardenedMain state / location. */
 SUPR3HARDENEDMAINSTATE  g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED;
+AssertCompileSize(g_enmSupR3HardenedMainState, sizeof(uint32_t));
+
+#ifdef RT_OS_WINDOWS
+/** Pointer to VBoxRT's RTLogRelPrintf function so we can write errors to the
+ * release log at runtime. */
+static PFNRTLOGRELPRINTF g_pfnRTLogRelPrintf = NULL;
+#endif
 
 
 /*******************************************************************************
@@ -224,11 +237,17 @@ static int suplibHardenedStrCopyEx(char *pszDst, size_t cbDst, ...)
 DECLNORETURN(void) suplibHardenedExit(RTEXITCODE rcExit)
 {
     for (;;)
+    {
 #ifdef RT_OS_WINDOWS
-        ExitProcess(rcExit);
+        if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+            ExitProcess(rcExit);
+        if (RtlExitUserProcess != NULL)
+            RtlExitUserProcess(rcExit);
+        NtTerminateProcess(NtCurrentProcess(), rcExit);
 #else
         _Exit(rcExit);
 #endif
+    }
 }
 
 
@@ -244,14 +263,18 @@ static void suplibHardenedPrintStrN(const char *pch, size_t cch)
     HANDLE hStdOut = NtCurrentPeb()->ProcessParameters->StandardOutput;
     if (hStdOut != NULL)
     {
-# if 0 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
-        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-        NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
-                    &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
-# else
-        DWORD cbWritten;
-        WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
-# endif
+        if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+        {
+            DWORD cbWritten;
+            WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
+        }
+        /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
+        else if (NtWriteFile != NULL && ((uintptr_t)hStdOut & 3) == 0)
+        {
+            IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+            NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
+                        &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
+        }
     }
 #else
     (void)write(2, pch, cch);
@@ -390,7 +413,8 @@ static DECLCALLBACK(size_t) suplibHardenedOutput(void *pvArg, const char *pachCh
         {
             suplibHardenedPrintStrN(pBuf->szBuf, pBuf->off);
 # ifdef RT_OS_WINDOWS
-            OutputDebugString(pBuf->szBuf);
+            if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+                OutputDebugString(pBuf->szBuf);
 # endif
             pBuf->off = 0;
             cbSpace = sizeof(pBuf->szBuf) - 1;
@@ -967,21 +991,20 @@ DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
 #ifdef RT_OS_WINDOWS
             if (g_hStartupLog == NULL)
             {
-                PRTUTF16 pwszPath;
-                int rc = RTStrToUtf16(pszLogFile, &pwszPath);
+                int rc = RTNtPathOpen(pszLogFile,
+                                      GENERIC_WRITE | SYNCHRONIZE,
+                                      FILE_ATTRIBUTE_NORMAL,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                      FILE_OPEN_IF,
+                                      FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                                      OBJ_CASE_INSENSITIVE,
+                                      &g_hStartupLog,
+                                      NULL);
                 if (RT_SUCCESS(rc))
-                {
-                    g_hStartupLog = CreateFileW(pwszPath,
-                                                GENERIC_WRITE,
-                                                FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                                NULL,
-                                                OPEN_ALWAYS,
-                                                FILE_ATTRIBUTE_NORMAL /*| FILE_FLAG_WRITE_THROUGH*/,
-                                                NULL);
-                    RTUtf16Free(pwszPath);
-                }
-                SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
-                             VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
+                    SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
+                                 VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
+                else
+                    g_hStartupLog = NULL;
             }
 #else
             //g_hStartupLog = open()
@@ -993,7 +1016,8 @@ DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
 DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
 {
 #ifdef RT_OS_WINDOWS
-    if (g_hStartupLog)
+    if (   g_hStartupLog != NULL
+        && g_cbStartupLog < 128*_1M)
     {
         char szBuf[5120];
         PCLIENT_ID pSelfId = &((PTEB)NtCurrentTeb())->ClientId;
@@ -1006,6 +1030,8 @@ DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
         if (!cch || szBuf[cch - 1] != '\n')
             szBuf[cch++] = '\n';
 
+        ASMAtomicAddU32(&g_cbStartupLog, (uint32_t)cch);
+
         IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         LARGE_INTEGER   Offset;
         Offset.QuadPart = -1; /* Write to end of file. */
@@ -1049,6 +1075,19 @@ DECLHIDDEN(void)   supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWha
     supR3HardenedLogV(pszMsgFmt, vaCopy);
     va_end(vaCopy);
 
+#ifdef RT_OS_WINDOWS
+    /*
+     * The release log.
+     */
+    if (g_pfnRTLogRelPrintf)
+    {
+        va_copy(vaCopy, va);
+        g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %s enmWhat=%d rc=%Rrc (%#x)\n", pszWhere, enmWhat, rc);
+        g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %N\n", pszMsgFmt, &vaCopy);
+        va_end(vaCopy);
+    }
+#endif
+
     /*
      * Then to the console.
      */
@@ -1083,37 +1122,51 @@ DECLHIDDEN(void)   supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWha
             break;
     }
 
-#ifdef SUP_HARDENED_SUID
     /*
-     * Drop any root privileges we might be holding, this won't return
-     * if it fails but end up calling supR3HardenedFatal[V].
+     * Finally, TrustedError if appropriate.
      */
-    supR3HardenedMainDropPrivileges();
-#endif /* SUP_HARDENED_SUID */
+    if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+    {
+#ifdef SUP_HARDENED_SUID
+        /*
+         * Drop any root privileges we might be holding, this won't return
+         * if it fails but end up calling supR3HardenedFatal[V].
+         */
+        supR3HardenedMainDropPrivileges();
+#endif
 
-    /*
-     * Now try resolve and call the TrustedError entry point if we can
-     * find it.  We'll fork before we attempt this because that way the
-     * session management in main will see us exiting immediately (if
-     * it's involved with us).
-     */
+        /*
+         * Now try resolve and call the TrustedError entry point if we can
+         * find it.  We'll fork before we attempt this because that way the
+         * session management in main will see us exiting immediately (if
+         * it's involved with us).
+         */
 #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
-    int pid = fork();
-    if (pid <= 0)
+        int pid = fork();
+        if (pid <= 0)
 #endif
-    {
-        static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
-        if (!s_fRecursive)
         {
-            s_fRecursive = true;
+            static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
+            if (!s_fRecursive)
+            {
+                s_fRecursive = true;
 
-            PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
-            if (pfnTrustedError)
-                pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
+                PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
+                if (pfnTrustedError)
+                    pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
 
-            s_fRecursive = false;
+                s_fRecursive = false;
+            }
         }
     }
+#if defined(RT_OS_WINDOWS)
+    /*
+     * Report the error to the parent if this happens during early VM init.
+     */
+    else if (   g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+             && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+        supR3HardenedWinReportErrorToParent(pszWhere, enmWhat, rc, pszMsgFmt, va);
+#endif
 
     /*
      * Quit
@@ -1139,8 +1192,29 @@ DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
     supR3HardenedLogV(pszFormat, vaCopy);
     va_end(vaCopy);
 
-    suplibHardenedPrintPrefix();
-    suplibHardenedPrintFV(pszFormat, va);
+#if defined(RT_OS_WINDOWS)
+    /*
+     * Report the error to the parent if this happens during early VM init.
+     */
+    if (   g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
+        && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+        supR3HardenedWinReportErrorToParent(NULL, kSupInitOp_Invalid, VERR_INTERNAL_ERROR, pszFormat, va);
+    else
+#endif
+    {
+#ifdef RT_OS_WINDOWS
+        if (g_pfnRTLogRelPrintf)
+        {
+            va_copy(vaCopy, va);
+            g_pfnRTLogRelPrintf("supR3HardenedFatalV: %N", pszFormat, &vaCopy);
+            va_end(vaCopy);
+        }
+#endif
+
+        suplibHardenedPrintPrefix();
+        suplibHardenedPrintFV(pszFormat, va);
+    }
+
     suplibHardenedExit(RTEXITCODE_FAILURE);
 }
 
@@ -1165,8 +1239,18 @@ DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat,
     supR3HardenedLogV(pszFormat, vaCopy);
     va_end(vaCopy);
 
+#ifdef RT_OS_WINDOWS
+    if (g_pfnRTLogRelPrintf)
+    {
+        va_copy(vaCopy, va);
+        g_pfnRTLogRelPrintf("supR3HardenedErrorV: %N", pszFormat, &vaCopy);
+        va_end(vaCopy);
+    }
+#endif
+
     suplibHardenedPrintPrefix();
     suplibHardenedPrintFV(pszFormat, va);
+
     return rc;
 }
 
@@ -1187,47 +1271,45 @@ DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, .
  *
  * @remarks This function will not return on failure.
  */
-static void supR3HardenedMainOpenDevice(void)
+DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
 {
-    int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/);
+    RTERRINFOSTATIC ErrInfo;
+    SUPINITOP       enmWhat = kSupInitOp_Driver;
+    int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
+                          &enmWhat, RTErrInfoInitStatic(&ErrInfo));
     if (RT_SUCCESS(rc))
         return;
 
+    if (RTErrInfoIsSet(&ErrInfo.Core))
+        supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
+
     switch (rc)
     {
         /** @todo better messages! */
         case VERR_VM_DRIVER_NOT_INSTALLED:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver not installed");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
         case VERR_VM_DRIVER_NOT_ACCESSIBLE:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver not accessible");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
         case VERR_VM_DRIVER_LOAD_ERROR:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_VM_DRIVER_LOAD_ERROR");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
         case VERR_VM_DRIVER_OPEN_ERROR:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_VM_DRIVER_OPEN_ERROR");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
         case VERR_VM_DRIVER_VERSION_MISMATCH:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver version mismatch");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
         case VERR_ACCESS_DENIED:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_ACCESS_DENIED");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
         case VERR_NO_MEMORY:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel memory allocation/mapping failed");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
         case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
         case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
         case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
         case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
         default:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Unknown rc=%d", rc);
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
     }
 }
 
@@ -1472,18 +1554,21 @@ static void supR3HardenedMainInitRuntime(uint32_t fFlags)
     if (!hMod)
         supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
                               "LoadLibrary \"%s\" failed (rc=%d)",
-                              szPath, GetLastError());
+                              szPath, RtlGetLastWin32Error());
     PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
     if (!pfnRTInitEx)
         supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
                               "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
-                              szPath, GetLastError());
+                              szPath, RtlGetLastWin32Error());
 
     PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
     if (!pfnSUPPreInit)
         supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
                               "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
-                              szPath, GetLastError());
+                              szPath, RtlGetLastWin32Error());
+
+    g_pfnRTLogRelPrintf = (PFNRTLOGRELPRINTF)GetProcAddress(hMod, SUP_HARDENED_SYM("RTLogRelPrintf"));
+    Assert(g_pfnRTLogRelPrintf);  /* Not fatal in non-strict builds. */
 
 #else
     /* the dlopen crowd */
@@ -1614,11 +1699,11 @@ static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName
     HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
     if (!hMod)
         supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
-                            szPath, GetLastError());
+                            szPath, RtlGetLastWin32Error());
     FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
     if (!pfn)
         supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
-                            szPath, GetLastError());
+                            szPath, RtlGetLastWin32Error());
     return (PFNSUPTRUSTEDMAIN)pfn;
 
 #else
@@ -1659,16 +1744,20 @@ static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName
 DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
 {
     SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
 
     /*
      * Note! At this point there is no IPRT, so we will have to stick
      * to basic CRT functions that everyone agree upon.
      */
-    g_pszSupLibHardenedProgName = pszProgName;
-    g_fSupHardenedMain          = fFlags;
+    g_pszSupLibHardenedProgName   = pszProgName;
+    g_fSupHardenedMain            = fFlags;
     g_SupPreInitData.u32Magic     = SUPPREINITDATA_MAGIC;
-    g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
     g_SupPreInitData.u32EndMagic  = SUPPREINITDATA_MAGIC;
+#ifdef RT_OS_WINDOWS
+    if (!g_fSupEarlyProcessInit)
+#endif
+        g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
 
 #ifdef SUP_HARDENED_SUID
 # ifdef RT_OS_LINUX
@@ -1677,7 +1766,6 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
      * *might* not be able to access /proc/self/exe after the seteuid call.
      */
     supR3HardenedGetFullExePath();
-
 # endif
 
     /*
@@ -1702,11 +1790,12 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
      * something we can put some kind of reliable trust in.  The first respawning aims
      * at dropping compatibility layers and process "security" solutions.
      */
-    if (   !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+    if (   !g_fSupEarlyProcessInit
+        && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
         && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
     {
         SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
-        supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV);
+        supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, false /*fAvastKludge*/);
         supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
         return supR3HardenedWinReSpawn(1 /*iWhich*/);
     }
@@ -1714,9 +1803,11 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
     /*
      * Windows: Initialize the image verification global data so we can verify the
      * signature of the process image and hook the core of the DLL loader API so we
-     * can check the signature of all DLLs mapped into the process.
+     * can check the signature of all DLLs mapped into the process.  (Already done
+     * by early VM process init.)
      */
-    supR3HardenedWinInit(fFlags);
+    if (!g_fSupEarlyProcessInit)
+        supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
 #endif /* RT_OS_WINDOWS */
 
     /*
@@ -1726,15 +1817,17 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
 
     /*
      * The next steps are only taken if we actually need to access the support
-     * driver.
+     * driver.  (Already done by early process init.)
      */
     if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
     {
 #ifdef RT_OS_WINDOWS
         /*
-         * Windows: Verify the process (repeated by the kernel later.
+         * Windows: Must have done early process init if we get here.
          */
-        supR3HardenedWinVerifyProcess();
+        if (!g_fSupEarlyProcessInit)
+            supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_Integrity, VERR_WRONG_ORDER,
+                                  "Early process init was somehow skipped.");
 
         /*
          * Windows: The second respawn.  This time we make a special arrangement
@@ -1747,12 +1840,13 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
         }
         SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
         supR3HardenedWinFlushLoaderCache();
-#endif /* RT_OS_WINDOWS */
 
+#else
         /*
          * Open the vboxdrv device.
          */
         supR3HardenedMainOpenDevice();
+#endif /* !RT_OS_WINDOWS */
     }
 
 #ifdef RT_OS_WINDOWS
@@ -1762,7 +1856,7 @@ DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int
     supR3HardenedWinEnableThreadCreation();
     supR3HardenedWinFlushLoaderCache();
     supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
-    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY;
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
 #endif
 
 #ifdef SUP_HARDENED_SUID
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
index ee5f313..8e34c8a 100644
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
@@ -410,7 +410,7 @@ DECLHIDDEN(int) supR3HardenedVerifyFixedDir(SUPINSTDIR enmDir, bool fFatal)
             }
             else
             {
-                int err = GetLastError();
+                int err = RtlGetLastWin32Error();
                 rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
                                         "supR3HardenedVerifyDir: Failed to open \"%s\": err=%d\n",
                                         szPath, err);
@@ -524,7 +524,7 @@ static int supR3HardenedVerifyFileOpen(PCSUPINSTFILE pFile, bool fFatal, intptr_
             }
             else
             {
-                int err = GetLastError();
+                int err = RtlGetLastWin32Error();
                 if (   !pFile->fOptional
                     || (    err != ERROR_FILE_NOT_FOUND
                         &&  (err != ERROR_PATH_NOT_FOUND || pFile->enmDir != kSupID_Testcase) ) )
@@ -602,7 +602,7 @@ static int supR3HardenedVerifyFileSignature(PCSUPINSTFILE pFile, PSUPVERIFIEDFIL
         if (fLeaveFileOpen && RT_SUCCESS(rc))
             pVerified->hFile = hFileOpened;
         else
-            CloseHandle((HANDLE)hFileOpened);
+            NtClose((HANDLE)hFileOpened);
     }
 
     return rc;
@@ -676,7 +676,7 @@ static int supR3HardenedVerifyFileInternal(int iFile, bool fFatal, bool fLeaveFi
                 pVerified->fValidated = true;
                 if (!fLeaveFileOpen)
                 {
-                    CloseHandle((HANDLE)pVerified->hFile);
+                    NtClose((HANDLE)pVerified->hFile);
                     pVerified->hFile = -1;
                 }
             }
@@ -1419,7 +1419,8 @@ static int supR3HardenedVerifyFsObject(PCSUPR3HARDENEDFSOBJSTATE pFsObjState, bo
 #endif
         if (fBad)
             return supR3HardenedSetError3(VERR_SUPLIB_WRITE_NON_SYS_GROUP, pErrInfo,
-                                          "The group is not a system group and it has write access to '", pszPath, "'");
+                                          "An unknown (and thus untrusted) group has write access to '", pszPath,
+                                          "' and we therefore cannot trust the directory content or that of any subdirectory");
     }
 
     /*
@@ -1738,11 +1739,11 @@ DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, RTHCUINTPTR hNa
         rc = supHardenedWinVerifyImageByHandleNoName(hVerify, fFlags, pErrInfo);
 #  endif
 # endif
-        CloseHandle(hVerify);
+        NtClose(hVerify);
     }
     else if (RT_SUCCESS(rc))
-        rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
-                           "Error %u trying to open (or duplicate handle for) '%s'", GetLastError(), pszFilename);
+        rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+                           "Error %u trying to open (or duplicate handle for) '%s'", RtlGetLastWin32Error(), pszFilename);
     if (RT_FAILURE(rc))
         return rc;
 #endif
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
index 69567b8..cd73baf 100644
--- a/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
+++ b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
@@ -185,7 +185,7 @@ static int suplibDarwinOpenService(PSUPLIBDATA pThis)
 }
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
index c5ca90d..f4c649b 100644
--- a/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
@@ -67,7 +67,7 @@
 
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
index e3d1a34..138f832 100644
--- a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
+++ b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
@@ -74,7 +74,7 @@
 
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
index 0f235ee..83145ce 100644
--- a/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
+++ b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
@@ -65,7 +65,7 @@
 
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
index 602854f..4e9ce2c 100644
--- a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
+++ b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
@@ -77,7 +77,7 @@
 
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Nothing to do if pre-inited.
diff --git a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h b/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h
deleted file mode 100644
index 2b8c8c8..0000000
--- a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-amd64-syscall-type-1.h
+++ /dev/null
@@ -1,78 +0,0 @@
-SYSCALL(0x30);
-SYSCALL(0x31);
-SYSCALL(0x32);
-SYSCALL(0x33);
-SYSCALL(0x34);
-SYSCALL(0x35);
-SYSCALL(0x36);
-SYSCALL(0x37);
-SYSCALL(0x38);
-SYSCALL(0x39);
-SYSCALL(0x3A);
-SYSCALL(0x3B);
-SYSCALL(0x3C);
-SYSCALL(0x3D);
-SYSCALL(0x3E);
-SYSCALL(0x3F);
-SYSCALL(0x40);
-SYSCALL(0x41);
-SYSCALL(0x42);
-SYSCALL(0x43);
-SYSCALL(0x44);
-SYSCALL(0x45);
-SYSCALL(0x46);
-SYSCALL(0x47); /* XP64/W2K3-64, Vista, Windows 7 */
-SYSCALL(0x48); /* Windows 8.0 */
-SYSCALL(0x49); /* windows 8.1 */
-SYSCALL(0x4A);
-SYSCALL(0x4B);
-SYSCALL(0x4C);
-SYSCALL(0x4D);
-SYSCALL(0x4E);
-SYSCALL(0x4F);
-SYSCALL(0x51);
-SYSCALL(0x52);
-SYSCALL(0x53);
-SYSCALL(0x54);
-SYSCALL(0x55);
-SYSCALL(0x56);
-SYSCALL(0x57);
-SYSCALL(0x59);
-SYSCALL(0x5A);
-SYSCALL(0x5B);
-SYSCALL(0x5C);
-SYSCALL(0x5D);
-SYSCALL(0x5E);
-SYSCALL(0x5F);
-SYSCALL(0x60);
-SYSCALL(0x61);
-SYSCALL(0x62);
-SYSCALL(0x63);
-SYSCALL(0x64);
-SYSCALL(0x65);
-SYSCALL(0x66);
-SYSCALL(0x67);
-SYSCALL(0x68);
-SYSCALL(0x69);
-SYSCALL(0x6A);
-SYSCALL(0x6B);
-SYSCALL(0x6C);
-SYSCALL(0x6D);
-SYSCALL(0x6E);
-SYSCALL(0x6F);
-SYSCALL(0x70);
-SYSCALL(0x71);
-SYSCALL(0x72);
-SYSCALL(0x73);
-SYSCALL(0x74);
-SYSCALL(0x75);
-SYSCALL(0x76);
-SYSCALL(0x77);
-SYSCALL(0x78);
-SYSCALL(0x79);
-SYSCALL(0x7A);
-SYSCALL(0x7B);
-SYSCALL(0x7C);
-SYSCALL(0x7D);
-SYSCALL(0x7E);
-SYSCALL(0x7F);
diff --git a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h b/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h
deleted file mode 100644
index f80a4d3..0000000
--- a/src/VBox/HostDrivers/Support/win/NtCreateSection-template-x86-syscall-type-1.h
+++ /dev/null
@@ -1,286 +0,0 @@
-SYSCALL(0x28);
-SYSCALL(0x29);
-SYSCALL(0x2A);
-SYSCALL(0x2B);
-SYSCALL(0x2C);
-SYSCALL(0x2D);
-SYSCALL(0x2E);
-SYSCALL(0x2F);
-SYSCALL(0x30);
-SYSCALL(0x31);
-
-SYSCALL(0x32); /* WinXP */
-SYSCALL(0x33);
-
-SYSCALL(0x34); /* W2K3 */
-SYSCALL(0x35);
-SYSCALL(0x36);
-SYSCALL(0x37);
-SYSCALL(0x38);
-SYSCALL(0x39);
-SYSCALL(0x3A);
-SYSCALL(0x3B);
-SYSCALL(0x3C);
-SYSCALL(0x3D);
-SYSCALL(0x3E);
-SYSCALL(0x3F);
-SYSCALL(0x40);
-SYSCALL(0x41);
-SYSCALL(0x42);
-SYSCALL(0x43);
-SYSCALL(0x44);
-SYSCALL(0x45);
-SYSCALL(0x46);
-SYSCALL(0x47);
-SYSCALL(0x48);
-SYSCALL(0x49);
-SYSCALL(0x4A);
-
-SYSCALL(0x4B); /* Vista */
-SYSCALL(0x4C);
-SYSCALL(0x4D);
-SYSCALL(0x4E);
-SYSCALL(0x4F);
-SYSCALL(0x50);
-SYSCALL(0x51);
-SYSCALL(0x52);
-SYSCALL(0x53);
-
-SYSCALL(0x54); /* Windows 7 */
-SYSCALL(0x55);
-SYSCALL(0x56);
-SYSCALL(0x57);
-SYSCALL(0x59);
-SYSCALL(0x5A);
-SYSCALL(0x5B);
-SYSCALL(0x5C);
-SYSCALL(0x5D);
-SYSCALL(0x5E);
-SYSCALL(0x5F);
-SYSCALL(0x60);
-SYSCALL(0x61);
-SYSCALL(0x62);
-SYSCALL(0x63);
-SYSCALL(0x64);
-SYSCALL(0x65);
-SYSCALL(0x66);
-SYSCALL(0x67);
-SYSCALL(0x68);
-SYSCALL(0x69);
-SYSCALL(0x6A);
-SYSCALL(0x6B);
-SYSCALL(0x6C);
-SYSCALL(0x6D);
-SYSCALL(0x6E);
-SYSCALL(0x6F);
-SYSCALL(0x70);
-SYSCALL(0x71);
-SYSCALL(0x72);
-SYSCALL(0x73);
-SYSCALL(0x74);
-SYSCALL(0x75);
-SYSCALL(0x76);
-SYSCALL(0x77);
-SYSCALL(0x78);
-SYSCALL(0x79);
-SYSCALL(0x7A);
-SYSCALL(0x7B);
-SYSCALL(0x7C);
-SYSCALL(0x7D);
-SYSCALL(0x7E);
-SYSCALL(0x7F);
-SYSCALL(0x80);
-SYSCALL(0x81);
-SYSCALL(0x82);
-SYSCALL(0x83);
-SYSCALL(0x84);
-SYSCALL(0x85);
-SYSCALL(0x86);
-SYSCALL(0x87);
-SYSCALL(0x88);
-SYSCALL(0x89);
-SYSCALL(0x8A);
-SYSCALL(0x8B);
-SYSCALL(0x8C);
-SYSCALL(0x8D);
-SYSCALL(0x8E);
-SYSCALL(0x8F);
-SYSCALL(0x90);
-SYSCALL(0x91);
-SYSCALL(0x92);
-SYSCALL(0x93);
-SYSCALL(0x94);
-SYSCALL(0x95);
-SYSCALL(0x96);
-SYSCALL(0x97);
-SYSCALL(0x98);
-SYSCALL(0x99);
-SYSCALL(0x9A);
-SYSCALL(0x9B);
-SYSCALL(0x9C);
-SYSCALL(0x9D);
-SYSCALL(0x9E);
-SYSCALL(0x9F);
-
-SYSCALL(0x100);
-SYSCALL(0x101);
-SYSCALL(0x102);
-SYSCALL(0x103);
-SYSCALL(0x104);
-SYSCALL(0x105);
-SYSCALL(0x106);
-SYSCALL(0x107);
-SYSCALL(0x108);
-SYSCALL(0x109);
-SYSCALL(0x10A);
-SYSCALL(0x10B);
-SYSCALL(0x10C);
-SYSCALL(0x10D);
-SYSCALL(0x10E);
-SYSCALL(0x10F);
-SYSCALL(0x110);
-SYSCALL(0x111);
-SYSCALL(0x112);
-SYSCALL(0x113);
-SYSCALL(0x114);
-SYSCALL(0x115);
-SYSCALL(0x116);
-SYSCALL(0x117);
-SYSCALL(0x118);
-SYSCALL(0x119);
-SYSCALL(0x11A);
-SYSCALL(0x11B);
-SYSCALL(0x11C);
-SYSCALL(0x11D);
-SYSCALL(0x11E);
-SYSCALL(0x11F);
-SYSCALL(0x120);
-SYSCALL(0x121);
-SYSCALL(0x122);
-SYSCALL(0x123);
-SYSCALL(0x124);
-SYSCALL(0x125);
-SYSCALL(0x126);
-SYSCALL(0x127);
-SYSCALL(0x128);
-SYSCALL(0x129);
-SYSCALL(0x12A);
-SYSCALL(0x12B);
-SYSCALL(0x12C);
-SYSCALL(0x12D);
-SYSCALL(0x12E);
-SYSCALL(0x12F);
-SYSCALL(0x130);
-SYSCALL(0x131);
-SYSCALL(0x132);
-SYSCALL(0x133);
-SYSCALL(0x134);
-SYSCALL(0x135);
-SYSCALL(0x136);
-SYSCALL(0x137);
-SYSCALL(0x138);
-SYSCALL(0x139);
-SYSCALL(0x13A);
-SYSCALL(0x13B);
-SYSCALL(0x13C);
-SYSCALL(0x13D);
-SYSCALL(0x13E);
-SYSCALL(0x13F);
-SYSCALL(0x140);
-SYSCALL(0x141);
-SYSCALL(0x142);
-SYSCALL(0x143);
-SYSCALL(0x144);
-SYSCALL(0x145);
-SYSCALL(0x146);
-SYSCALL(0x147);
-SYSCALL(0x148);
-SYSCALL(0x149);
-SYSCALL(0x14A);
-SYSCALL(0x14B);
-SYSCALL(0x14C);
-SYSCALL(0x14D);
-SYSCALL(0x14E);
-SYSCALL(0x14F);
-SYSCALL(0x150);
-SYSCALL(0x151);
-SYSCALL(0x152);
-SYSCALL(0x153);
-
-SYSCALL(0x154); /* Windows 8.1 */
-SYSCALL(0x155);
-SYSCALL(0x156);
-SYSCALL(0x157);
-SYSCALL(0x158);
-SYSCALL(0x159);
-SYSCALL(0x15A);
-SYSCALL(0x15B);
-SYSCALL(0x15C);
-SYSCALL(0x15D);
-SYSCALL(0x15E);
-SYSCALL(0x15F);
-SYSCALL(0x160);
-SYSCALL(0x161);
-SYSCALL(0x162);
-SYSCALL(0x163);
-SYSCALL(0x164);
-SYSCALL(0x165);
-SYSCALL(0x166);
-SYSCALL(0x167);
-SYSCALL(0x168);
-SYSCALL(0x169);
-SYSCALL(0x16A);
-SYSCALL(0x16B);
-SYSCALL(0x16C);
-SYSCALL(0x16D);
-SYSCALL(0x16E);
-SYSCALL(0x16F);
-SYSCALL(0x170);
-SYSCALL(0x171);
-SYSCALL(0x172);
-SYSCALL(0x173);
-SYSCALL(0x174);
-SYSCALL(0x175);
-SYSCALL(0x176);
-SYSCALL(0x177);
-SYSCALL(0x178);
-SYSCALL(0x179);
-SYSCALL(0x17A);
-SYSCALL(0x17B);
-SYSCALL(0x17C);
-SYSCALL(0x17D);
-SYSCALL(0x17E);
-SYSCALL(0x17F);
-SYSCALL(0x180);
-SYSCALL(0x181);
-SYSCALL(0x182);
-SYSCALL(0x183);
-SYSCALL(0x184);
-SYSCALL(0x185);
-SYSCALL(0x186);
-SYSCALL(0x187);
-SYSCALL(0x188);
-SYSCALL(0x189);
-SYSCALL(0x18A);
-SYSCALL(0x18B);
-SYSCALL(0x18C);
-SYSCALL(0x18D);
-SYSCALL(0x18E);
-SYSCALL(0x18F);
-SYSCALL(0x190);
-SYSCALL(0x191);
-SYSCALL(0x192);
-SYSCALL(0x193);
-SYSCALL(0x194);
-SYSCALL(0x195);
-SYSCALL(0x196);
-SYSCALL(0x197);
-SYSCALL(0x198);
-SYSCALL(0x199);
-SYSCALL(0x19A);
-SYSCALL(0x19B);
-SYSCALL(0x19C);
-SYSCALL(0x19D);
-SYSCALL(0x19E);
-SYSCALL(0x19F);
-
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
index 357ff8e..43f1d7f 100644
--- a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
@@ -40,6 +40,8 @@
 #include <iprt/mem.h>
 #include <iprt/process.h>
 #include <iprt/power.h>
+#include <iprt/rand.h>
+#include <iprt/semaphore.h>
 #include <iprt/spinlock.h>
 #include <iprt/string.h>
 #include <VBox/log.h>
@@ -60,19 +62,23 @@
 /** The Pool tag (VBox). */
 #define SUPDRV_NT_POOL_TAG  'xoBV'
 
-/** NT device name for system access. */
-#define DEVICE_NAME_NT_SYS      L"\\Device\\VBoxDrv"
 /** NT device name for user access. */
-#define DEVICE_NAME_NT_USR      L"\\Device\\VBoxDrvU"
+#define DEVICE_NAME_NT_USR          L"\\Device\\VBoxDrvU"
 #ifdef VBOX_WITH_HARDENING
-/** NT device name for hardened stub access. */
-# define DEVICE_NAME_NT_STUB    L"\\Device\\VBoxDrvStub"
-
 /** Macro for checking for deflecting calls to the stub device. */
 # define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
-    do { if ((a_pDevObj) == g_pDevObjStub) supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); } while (0)
+    do { if ((a_pDevObj) == g_pDevObjStub) \
+            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+    } while (0)
+/** Macro for checking for deflecting calls to the stub and error info
+ *  devices. */
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
+    do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
+            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+    } while (0)
 #else
-# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp)                 do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp)   do {} while (0)
 #endif
 
 /** Enables the fast I/O control code path. */
@@ -107,20 +113,55 @@ typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
 #ifdef VBOX_WITH_HARDENING
 
 /**
- * Device extension used by VBoxDrvS.
+ * Device extension used by VBoxDrvStub.
  */
 typedef struct SUPDRVDEVEXTSTUB
 {
     /** Common header. */
     SUPDRVDEVEXTUSR     Common;
 } SUPDRVDEVEXTSTUB;
-/** Pointer to the VBoxDrvS device extension. */
+/** Pointer to the VBoxDrvStub device extension. */
 typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
 /** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
 #define SUPDRVDEVEXTSTUB_COOKIE      UINT32_C(0x90abcdef)
 
 
 /**
+ * Device extension used by VBoxDrvErrorInfo.
+ */
+typedef struct SUPDRVDEVEXTERRORINFO
+{
+    /** Common header. */
+    SUPDRVDEVEXTUSR     Common;
+} SUPDRVDEVEXTERRORINFO;
+/** Pointer to the VBoxDrvErrorInfo device extension. */
+typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
+/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
+#define SUPDRVDEVEXTERRORINFO_COOKIE      UINT32_C(0xBadC0ca0)
+
+/**
+ * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
+ */
+typedef struct SUPDRVNTERRORINFO
+{
+    /** The list entry (in g_ErrorInfoHead). */
+    RTLISTNODE      ListEntry;
+    /** The ID of the process this error info belongs to.  */
+    HANDLE          hProcessId;
+    /** The ID of the thread owning this info. */
+    HANDLE          hThreadId;
+    /** Milliseconds createion timestamp (for cleaning up).  */
+    uint64_t        uCreatedMsTs;
+    /** Number of bytes of valid info. */
+    uint32_t        cchErrorInfo;
+    /** The error info. */
+    char            szErrorInfo[2048];
+} SUPDRVNTERRORINFO;
+/** Pointer to error info. */
+typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
+
+
+/**
  * The kind of process we're protecting.
  */
 typedef enum SUPDRVNTPROTECTKIND
@@ -165,6 +206,9 @@ typedef struct SUPDRVNTPROTECT
     uint32_t volatile   cRefs;
     /** The kind of process we're protecting. */
     SUPDRVNTPROTECTKIND volatile enmProcessKind;
+    /** 7,: Hack to allow the supid themes service duplicate handle privileges to
+     *  our process. */
+    bool                fThemesFirstProcessCreateHandle : 1;
     /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
      *  NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
     bool                fFirstProcessCreateHandle : 1;
@@ -174,15 +218,16 @@ typedef struct SUPDRVNTPROTECT
     /** 8.1: Hack to allow more rights to the handle returned by
      *  NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
     bool                fCsrssFirstProcessCreateHandle : 1;
-    /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSR
-     *  during process creation. Only applicable to VmProcessUnconfirmed. */
-    bool                fCsrssFirstProcessDuplicateHandle : 1;
-    /** 7,: Hack to allow the supid themes service duplicate handle privileges to
-     *  our process. */
-    bool                fThemesFirstProcessCreateHandle : 1;
+    /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSRSS
+     * during process creation. Only applicable to VmProcessUnconfirmed.  On
+     * 32-bit systems we allow two as ZoneAlarm's system call hooks has been
+     * observed to do some seemingly unnecessary duplication work. */
+    int32_t volatile    cCsrssFirstProcessDuplicateHandle;
 
     /** The parent PID for VM processes, otherwise NULL. */
     HANDLE              hParentPid;
+    /** The TID of the thread opening VBoxDrv or VBoxDrvStub, NULL if not opened. */
+    HANDLE              hOpenTid;
     /** The PID of the CSRSS process associated with this process. */
     HANDLE              hCsrssPid;
     /** Pointer to the CSRSS process structure (referenced). */
@@ -196,7 +241,7 @@ typedef struct SUPDRVNTPROTECT
         struct SUPDRVNTPROTECT *pChild;
         /** A process in the VmProcessUnconfirmed state will keep a weak
          * reference to the parent's protection structure so it can clean up the pChild
-         * refernece the parent has to it. */
+         * reference the parent has to it. */
         struct SUPDRVNTPROTECT *pParent;
     } u;
 } SUPDRVNTPROTECT;
@@ -207,6 +252,8 @@ typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
 /** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
 # define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
 
+/** Pointer to ObGetObjectType. */
+typedef POBJECT_TYPE (NTAPI *PFNOBGETOBJECTTYPE)(PVOID);
 /** Pointer to ObRegisterCallbacks. */
 typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
 /** Pointer to ObUnregisterCallbacks. */
@@ -217,6 +264,8 @@ typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_N
 typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
 /** Pointer to PsIsProtectedProcessLight. */
 typedef BOOLEAN  (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
+/** Pointer to ZwAlpcCreatePort. */
+typedef NTSTATUS (NTAPI *PFNZWALPCCREATEPORT)(PHANDLE, POBJECT_ATTRIBUTES, struct _ALPC_PORT_ATTRIBUTES *);
 
 #endif /* VBOX_WITH_HARDENINIG */
 
@@ -237,6 +286,7 @@ static NTSTATUS _stdcall   VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP p
 static int                 VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
 static NTSTATUS _stdcall   VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static VOID     _stdcall   VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
+static NTSTATUS _stdcall   VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static NTSTATUS _stdcall   VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static NTSTATUS            VBoxDrvNtErr2NtStatus(int rc);
 #ifdef VBOX_WITH_HARDENING
@@ -250,6 +300,8 @@ static int                  supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT
 static int                  supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
 
 static bool                 supdrvNtIsDebuggerAttached(void);
+static void                 supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
+
 #endif
 
 
@@ -315,6 +367,8 @@ static AVLPVTREE                    g_NtProtectTree  = NULL;
 static PVOID                        g_pvObCallbacksCookie = NULL;
 /** Combined windows NT version number.  See SUP_MAKE_NT_VER_COMBINED. */
 uint32_t                            g_uNtVerCombined = 0;
+/** Pointer to ObGetObjectType if available.. */
+static PFNOBGETOBJECTTYPE           g_pfnObGetObjectType = NULL;
 /** Pointer to ObRegisterCallbacks if available.. */
 static PFNOBREGISTERCALLBACKS       g_pfnObRegisterCallbacks = NULL;
 /** Pointer to ObUnregisterCallbacks if available.. */
@@ -325,6 +379,8 @@ static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutine
 static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
 /** Pointer to PsIsProtectedProcessLight. */
 static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
+/** Pointer to ZwAlpcCreatePort. */
+static PFNZWALPCCREATEPORT          g_pfnZwAlpcCreatePort = NULL;
 
 # ifdef RT_ARCH_AMD64
 extern "C" {
@@ -336,6 +392,18 @@ PFNRT                               g_pfnKiServiceLinkage  = NULL;
 PFNRT                               g_pfnKiServiceInternal = NULL;
 }
 # endif
+/** The primary ALPC port object type. (LpcPortObjectType at init time.) */
+static POBJECT_TYPE                 g_pAlpcPortObjectType1 = NULL;
+/** The secondary ALPC port object type. (Sampled at runtime.) */
+static POBJECT_TYPE volatile        g_pAlpcPortObjectType2 = NULL;
+
+/** Pointer to the error information device instance. */
+static PDEVICE_OBJECT               g_pDevObjErrorInfo = NULL;
+/** Fast mutex semaphore protecting the error info list. */
+static RTSEMMUTEX                   g_hErrorInfoLock = NIL_RTSEMMUTEX;
+/** Head of the error info (SUPDRVNTERRORINFO). */
+static RTLISTANCHOR                 g_ErrorInfoHead;
+
 #endif
 
 
@@ -351,14 +419,14 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
      * System device.
      */
     UNICODE_STRING DevName;
-    RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_SYS);
+    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
     NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
     if (NT_SUCCESS(rcNt))
     {
         /*
          * User device.
          */
-        RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_USR);
+        RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
         rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
         if (NT_SUCCESS(rcNt))
         {
@@ -370,7 +438,7 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
             /*
              * Hardened stub device.
              */
-            RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_STUB);
+            RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
             rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
             if (NT_SUCCESS(rcNt))
             {
@@ -379,11 +447,33 @@ static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
                     PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
                     pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
                     pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTSTUB_COOKIE;
-#endif
 
-                    /* Done. */
-                    return rcNt;
+                    /*
+                     * Hardened error information device.
+                     */
+                    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+                    rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
+                                          &g_pDevObjErrorInfo);
+                    if (NT_SUCCESS(rcNt))
+                    {
+                        g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
+
+                        if (NT_SUCCESS(rcNt))
+                        {
+                            PSUPDRVDEVEXTERRORINFO pDevExtStub = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+                            pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
+                            pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTERRORINFO_COOKIE;
+
+#endif
+                            /* Done. */
+                            return rcNt;
 #ifdef VBOX_WITH_HARDENING
+                        }
+
+                        /* Bail out. */
+                        IoDeleteDevice(g_pDevObjErrorInfo);
+                        g_pDevObjErrorInfo = NULL;
+                    }
                 }
 
                 /* Bail out. */
@@ -416,9 +506,16 @@ static void vboxdrvNtDestroyDevices(void)
         PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
         pDevExtStub->Common.pMainDrvExt = NULL;
     }
+    if (g_pDevObjErrorInfo)
+    {
+        PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+        pDevExtErrorInfo->Common.pMainDrvExt = NULL;
+    }
 #endif
 
 #ifdef VBOX_WITH_HARDENING
+    IoDeleteDevice(g_pDevObjErrorInfo);
+    g_pDevObjErrorInfo = NULL;
     IoDeleteDevice(g_pDevObjStub);
     g_pDevObjStub = NULL;
 #endif
@@ -493,7 +590,7 @@ ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
                     pDrvObj->MajorFunction[IRP_MJ_CLOSE]                    = VBoxDrvNtClose;
                     pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = VBoxDrvNtDeviceControl;
                     pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]  = VBoxDrvNtInternalDeviceControl;
-                    pDrvObj->MajorFunction[IRP_MJ_READ]                     = VBoxDrvNtNotSupportedStub;
+                    pDrvObj->MajorFunction[IRP_MJ_READ]                     = VBoxDrvNtRead;
                     pDrvObj->MajorFunction[IRP_MJ_WRITE]                    = VBoxDrvNtNotSupportedStub;
 
 #ifdef VBOXDRV_WITH_FAST_IO
@@ -644,6 +741,16 @@ NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
 
         rcNt = STATUS_ACCESS_DENIED;
     }
+#ifdef VBOX_WITH_HARDENING
+    /*
+     * Anyone can open the error device.
+     */
+    else if (pDevObj == g_pDevObjErrorInfo)
+    {
+        pFileObj->FsContext = NULL;
+        return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
+    }
+#endif
     else
     {
 #if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
@@ -819,6 +926,8 @@ NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
             pFileObj->FsContext = NULL;
         }
     }
+    else if (pDevObj == g_pDevObjErrorInfo)
+        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
     else
 #endif
     {
@@ -859,6 +968,8 @@ NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
             pFileObj->FsContext = NULL;
         }
     }
+    else if (pDevObj == g_pDevObjErrorInfo)
+        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
     else
 #endif
     {
@@ -898,13 +1009,22 @@ static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOL
                                                      PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
                                                      PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
 {
-    PSUPDRVDEVEXT   pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
+    /*
+     * Only the normal devices, not the stub or error info ones.
+     */
+    if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
+    {
+        pIoStatus->Status      = STATUS_NOT_SUPPORTED;
+        pIoStatus->Information = 0;
+        return TRUE;
+    }
 
     /*
      * Check the input a little bit and get a the session references.
      */
-    PSUPDRVSESSION  pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
-                                                          (PSUPDRVSESSION *)&pFileObj->FsContext);
+    PSUPDRVDEVEXT  pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
+    PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
+                                                         (PSUPDRVSESSION *)&pFileObj->FsContext);
     if (!pSession)
     {
         pIoStatus->Status      = STATUS_TRUST_FAILURE;
@@ -1083,7 +1203,7 @@ static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOL
  */
 NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
 {
-    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
 
     PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
     PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
@@ -1225,7 +1345,7 @@ static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSes
  */
 NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
 {
-    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
 
     PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
     PIO_STACK_LOCATION  pStack   = IoGetCurrentIrpStackLocation(pIrp);
@@ -1309,6 +1429,115 @@ NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pI
 
 
 /**
+ * Implementation of the read major function for VBoxDrvErrorInfo.
+ *
+ * This is a stub function for the other devices.
+ *
+ * @returns NT status code.
+ * @param   pDevObj             The device object.
+ * @param   pIrp                The I/O request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+    Log(("VBoxDrvNtRead\n"));
+
+    NTSTATUS rcNt;
+    pIrp->IoStatus.Information = 0;
+
+#ifdef VBOX_WITH_HARDENING
+    /*
+     * VBoxDrvErrorInfo?
+     */
+    if (pDevObj == g_pDevObjErrorInfo)
+    {
+        PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+        if (   pStack
+            && (pIrp->Flags & IRP_BUFFERED_IO))
+        {
+            /*
+             * Look up the process error information.
+             */
+            HANDLE hCurThreadId  = PsGetCurrentThreadId();
+            HANDLE hCurProcessId = PsGetCurrentProcessId();
+            int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+            if (RT_SUCCESS(rc))
+            {
+                PSUPDRVNTERRORINFO  pCur;
+                RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
+                {
+                    if (   pCur->hProcessId == hCurProcessId
+                        && pCur->hThreadId  == hCurThreadId)
+                        break;
+                }
+
+                /*
+                 * Did we find error info and is the caller requesting data within it?
+                 * If so, cehck the destination buffer and copy the data into it.
+                 */
+                if (   pCur
+                    && pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
+                    && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
+                {
+                    PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
+                    if (pvDstBuf)
+                    {
+                        uint32_t offRead  = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
+                        uint32_t cbToRead = pCur->cchErrorInfo - (uint32_t)offRead;
+                        if (cbToRead > pStack->Parameters.Read.Length)
+                        {
+                            cbToRead = pStack->Parameters.Read.Length;
+                            RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
+                        }
+                        memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
+                        pIrp->IoStatus.Information = cbToRead;
+
+                        rcNt = STATUS_SUCCESS;
+                    }
+                    else
+                        rcNt = STATUS_INVALID_ADDRESS;
+                }
+                /*
+                 * End of file. Free the info.
+                 */
+                else if (pCur)
+                {
+                    RTListNodeRemove(&pCur->ListEntry);
+                    RTMemFree(pCur);
+                    rcNt = STATUS_END_OF_FILE;
+                }
+                /*
+                 * We found no error info. Return EOF.
+                 */
+                else
+                    rcNt = STATUS_END_OF_FILE;
+
+                RTSemMutexRelease(g_hErrorInfoLock);
+            }
+            else
+                rcNt = STATUS_UNSUCCESSFUL;
+        }
+        else
+            rcNt = STATUS_INVALID_PARAMETER;
+    }
+    else
+#endif /* VBOX_WITH_HARDENING */
+    {
+        /*
+         * Stub.
+         */
+        rcNt = STATUS_NOT_SUPPORTED;
+    }
+
+    /*
+     * Complete the request.
+     */
+    pIrp->IoStatus.Status = rcNt;
+    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+    return rcNt;
+}
+
+
+/**
  * Stub function for functions we don't implemented.
  *
  * @returns STATUS_NOT_SUPPORTED
@@ -1900,6 +2129,157 @@ static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
 
 
 /**
+ * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
+ *
+ * @returns true if done, false if not.
+ * @param   pwszPortNm          The port path.
+ * @param   ppObjType           The object type return variable, updated when
+ *                              returning true.
+ */
+static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
+{
+    bool fDone = false;
+
+    UNICODE_STRING UniStrPortNm;
+    UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
+    UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
+    UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
+
+    OBJECT_ATTRIBUTES ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+    HANDLE hPort;
+    NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
+    if (NT_SUCCESS(rcNt))
+    {
+        PVOID pvObject;
+        rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
+                                         KernelMode, &pvObject, NULL /*pHandleInfo*/);
+        if (NT_SUCCESS(rcNt))
+        {
+            POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
+            if (pObjType)
+            {
+                SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
+                *ppObjType = pObjType;
+                fDone = true;
+            }
+            ObDereferenceObject(pvObject);
+        }
+        NtClose(hPort);
+    }
+    return fDone;
+}
+
+
+/**
+ * Attempts to retrieve the ALPC Port object type.
+ *
+ * We've had at least three reports that using LpcPortObjectType when trying to
+ * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
+ * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
+ * exported) so that it differs from the actual ApiPort type, or maybe this
+ * unknown entity is intercepting our attempt to reference the port and
+ * tries to mislead us.  The paranoid explanataion is of course that some evil
+ * root kit like software is messing with the OS, however, it's possible that
+ * this is valid kernel behavior that 99.8% of our users and 100% of the
+ * developers are not triggering for some reason.
+ *
+ * The code here creates an ALPC port object and gets it's type.  It will cache
+ * the result in g_pAlpcPortObjectType2 on success.
+ *
+ * @returns Object type.
+ * @param   uSessionId      The session id.
+ * @param   pszSessionId    The session id formatted as a string.
+ */
+static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
+{
+    POBJECT_TYPE pObjType = *LpcPortObjectType;
+
+    if (   g_pfnZwAlpcCreatePort
+        && g_pfnObGetObjectType)
+    {
+        int     rc;
+        ssize_t cchTmp; NOREF(cchTmp);
+        char    szTmp[16];
+        RTUTF16 wszPortNm[128];
+        size_t  offRand;
+
+        /*
+         * First attempt is in the session directory.
+         */
+        rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
+        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
+        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
+        cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
+        Assert(cchTmp > 0);
+        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
+        offRand = RTUtf16Len(wszPortNm);
+        cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+        Assert(cchTmp > 0);
+        rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+        AssertRCSuccess(rc);
+
+        bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+        if (!fDone)
+        {
+            wszPortNm[offRand] = '\0';
+            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
+            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+            AssertRCSuccess(rc);
+
+            fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+        }
+        if (!fDone)
+        {
+            /*
+             * Try base names.
+             */
+            if (uSessionId == 0)
+                rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
+            else
+            {
+                rc  = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
+                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
+                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
+            }
+            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
+            Assert(cchTmp > 0);
+            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
+            offRand = RTUtf16Len(wszPortNm);
+            cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+            Assert(cchTmp > 0);
+            rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+            AssertRCSuccess(rc);
+
+            bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+            if (!fDone)
+            {
+                wszPortNm[offRand] = '\0';
+                cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
+                Assert(cchTmp > 0);
+                rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
+                AssertRCSuccess(rc);
+
+                fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
+            }
+        }
+
+        /* Cache the result in g_pAlpcPortObjectType2. */
+        if (   g_pAlpcPortObjectType2 == NULL
+            && pObjType != g_pAlpcPortObjectType1
+            && fDone)
+            g_pAlpcPortObjectType2 = pObjType;
+
+    }
+
+    return pObjType;
+}
+
+
+/**
  * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
  * current process.
  *
@@ -1921,19 +2301,23 @@ static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
      * We'll try use the ApiPort LPC object for the session we're in to track
      * down the CSRSS process. So, we start by constructing a path to it.
      */
-    int rc;
+    int         rc;
     uint32_t    uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
+    char        szSessionId[16];
     WCHAR       wszApiPort[48];
     if (uSessionId == 0)
+    {
+        szSessionId[0] = '0';
+        szSessionId[1] = '\0';
         rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
+    }
     else
     {
-        char szTmp[64];
-        ssize_t cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), uSessionId, 10, 0, 0, 0);
+        ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
         AssertReturn(cchTmp > 0, (int)cchTmp);
         rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
         if (RT_SUCCESS(rc))
-            rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szTmp);
+            rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
         if (RT_SUCCESS(rc))
             rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
     }
@@ -1952,14 +2336,35 @@ static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
                                             0,
                                             NULL /*pAccessState*/,
                                             STANDARD_RIGHTS_READ,
-                                            *LpcPortObjectType,
+                                            g_pAlpcPortObjectType1,
                                             KernelMode,
                                             NULL /*pvParseContext*/,
                                             &pvApiPortObj);
+    if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
+        && g_pAlpcPortObjectType2 != NULL)
+        rcNt = ObReferenceObjectByName(&ApiPortStr,
+                                       0,
+                                       NULL /*pAccessState*/,
+                                       STANDARD_RIGHTS_READ,
+                                       g_pAlpcPortObjectType2,
+                                       KernelMode,
+                                       NULL /*pvParseContext*/,
+                                       &pvApiPortObj);
+    if (   rcNt == STATUS_OBJECT_TYPE_MISMATCH
+        && g_pfnObGetObjectType
+        && g_pfnZwAlpcCreatePort)
+        rcNt = ObReferenceObjectByName(&ApiPortStr,
+                                       0,
+                                       NULL /*pAccessState*/,
+                                       STANDARD_RIGHTS_READ,
+                                       supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
+                                       KernelMode,
+                                       NULL /*pvParseContext*/,
+                                       &pvApiPortObj);
     if (!NT_SUCCESS(rcNt))
     {
         SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
-        return VERR_SUPDRV_APIPORT_OPEN_ERROR;
+        return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
     }
 
     /*
@@ -2176,6 +2581,31 @@ static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
 /** @name Process Creation Callbacks.
  * @{ */
 
+
+/**
+ * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
+ *
+ * @param   hProcessId          The ID of the dead process.
+ */
+static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
+{
+    int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+    if (RT_SUCCESS(rc))
+    {
+        PSUPDRVNTERRORINFO pCur, pNext;
+        RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
+        {
+            if (pCur->hProcessId == hProcessId)
+            {
+                RTListNodeRemove(&pCur->ListEntry);
+                RTMemFree(pCur);
+            }
+        }
+        RTSemMutexRelease(g_hErrorInfoLock);
+    }
+}
+
+
 /**
  * Common worker used by the process creation hooks as well as the process
  * handle creation hooks to check if a VM process is being created.
@@ -2239,7 +2669,7 @@ static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE
         pNtChild->fFirstProcessCreateHandle = true;
         pNtChild->fFirstThreadCreateHandle = true;
         pNtChild->fCsrssFirstProcessCreateHandle = true;
-        pNtChild->fCsrssFirstProcessDuplicateHandle = true;
+        pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
         pNtChild->fThemesFirstProcessCreateHandle = true;
         pNtChild->hParentPid = pNtParent->AvlCore.Key;
         pNtChild->hCsrssPid = pNtParent->hCsrssPid;
@@ -2422,7 +2852,10 @@ supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, B
      * Process termination, do clean ups.
      */
     else
+    {
         supdrvNtProtectUnprotectDeadProcess(hNewPid);
+        supdrvNtErrorInfoCleanupProcess(hNewPid);
+    }
 }
 
 
@@ -2478,7 +2911,10 @@ supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNew
      * Process termination, do clean ups.
      */
     else
+    {
         supdrvNtProtectUnprotectDeadProcess(hNewPid);
+        supdrvNtErrorInfoCleanupProcess(hNewPid);
+    }
 }
 
 /** @} */
@@ -2620,6 +3056,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
                     && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
                     && pNtProtect->fCsrssFirstProcessCreateHandle
                     && pOpInfo->KernelHandle == 0
+                    && ExGetPreviousMode() == UserMode
                     && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
                 {
                     pNtProtect->fCsrssFirstProcessCreateHandle = false;
@@ -2646,6 +3083,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
                     && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
                     && pNtProtect->fThemesFirstProcessCreateHandle
                     && pOpInfo->KernelHandle == 0
+                    && ExGetPreviousMode() == UserMode
                     && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
                 {
                     pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
@@ -2686,15 +3124,16 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
                    This is the CSRSS.EXE end of special case #1. */
                 if (   g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
                     && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
-                    && pNtProtect->fCsrssFirstProcessDuplicateHandle
+                    && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
                     && pOpInfo->KernelHandle == 0
+                    && pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires
                     &&    pNtProtect->hParentPid
                        == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
                     && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
-                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
+                    && ExGetPreviousMode() == UserMode
+                    && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
                 {
-                    pNtProtect->fCsrssFirstProcessDuplicateHandle = false;
-                    if (pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
+                    if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
                     {
                         /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
                            PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
@@ -2838,6 +3277,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
                     && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
                     && pNtProtect->fFirstThreadCreateHandle
                     && pOpInfo->KernelHandle == 0
+                    && ExGetPreviousMode() == UserMode
                     && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
                 {
                     if (   !pOpInfo->KernelHandle
@@ -2860,6 +3300,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
                     && (   (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
                         || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
                     && pOpInfo->KernelHandle == 0
+                    && ExGetPreviousMode() == UserMode
                     && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
                 {
                     fAllowedRights |= THREAD_IMPERSONATE;
@@ -2904,6 +3345,7 @@ supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMAT
                         || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
                     && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
                     && pOpInfo->KernelHandle == 0
+                    && ExGetPreviousMode() == UserMode
                     && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
                 {
                     fAllowedRights |= THREAD_IMPERSONATE;
@@ -2982,6 +3424,7 @@ static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUP
     pNtProtect->cRefs                        = 1;
     pNtProtect->enmProcessKind               = enmProcessKind;
     pNtProtect->hParentPid                   = NULL;
+    pNtProtect->hOpenTid                     = NULL;
     pNtProtect->hCsrssPid                    = NULL;
     pNtProtect->pCsrssProcess                = NULL;
 
@@ -3041,7 +3484,7 @@ static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
                 pNtProtect->u.pChild   = NULL;
                 pChild->u.pParent      = NULL;
                 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
-                uint32_t cChildRefs = ASMAtomicIncU32(&pChild->cRefs);
+                uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
                 if (!cChildRefs)
                     pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
                 else
@@ -3087,14 +3530,114 @@ static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
 
 
 /**
+ * Validates a few facts about the stub process when the VM process opens
+ * vboxdrv.
+ *
+ * This makes sure the stub process is still around and that it has neither
+ * debugger nor extra threads in it.
+ *
+ * @returns VBox status code.
+ * @param   pNtProtect          The unconfirmed VM process currently trying to
+ *                              open vboxdrv.
+ * @param   pErrInfo            Additional error information.
+ */
+static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
+{
+    /*
+     * Grab a reference to the parent stub process.
+     */
+    SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
+    PSUPDRVNTPROTECT    pNtStub = NULL;
+    RTSpinlockAcquire(g_hNtProtectLock);
+    if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
+    {
+        pNtStub = pNtProtect->u.pParent; /* weak reference. */
+        if (pNtStub)
+        {
+            enmStub = pNtStub->enmProcessKind;
+            if (enmStub == kSupDrvNtProtectKind_StubParent)
+            {
+                uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
+                Assert(cRefs > 0 && cRefs < 1024);
+            }
+            else
+                pNtStub = NULL;
+        }
+    }
+    RTSpinlockRelease(g_hNtProtectLock);
+
+    /*
+     * We require the stub process to be present.
+     */
+    if (!pNtStub)
+        return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
+
+    /*
+     * Open the parent process and thread so we can check for debuggers and unwanted threads.
+     */
+    int rc;
+    PEPROCESS pStubProcess;
+    NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
+    if (NT_SUCCESS(rcNt))
+    {
+        HANDLE hStubProcess;
+        rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
+                                     0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
+        if (NT_SUCCESS(rcNt))
+        {
+            PETHREAD pStubThread;
+            rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
+            if (NT_SUCCESS(rcNt))
+            {
+                HANDLE hStubThread;
+                rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
+                                             0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
+                if (NT_SUCCESS(rcNt))
+                {
+                    /*
+                     * Do some simple sanity checking.
+                     */
+                    rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
+                    if (RT_SUCCESS(rc))
+                        rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
+
+                    /* Clean up. */
+                    rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+                }
+                else
+                    rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
+                                       "Error opening stub thread %p (tid %p, pid %p): %#x",
+                                       pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
+            }
+            else
+                rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
+                                   "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
+            rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+        }
+        else
+            rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
+                               "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
+        ObDereferenceObject(pStubProcess);
+    }
+    else
+        rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
+                           "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
+
+    supdrvNtProtectRelease(pNtStub);
+    return rc;
+}
+
+
+/**
  * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
  * process and its thread.
  *
  * @returns VBox status code.
  * @param   pNtProtect          The NT protect structure for getting information
  *                              about special processes.
+ * @param   pErrInfo            Where to return additional error details.
  */
-static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect)
+static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
 {
     /*
      * What to protect.
@@ -3123,13 +3666,14 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
             RTMemFree(pbBuf);
             pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
             if (!pbBuf)
-                return VERR_NO_MEMORY;
+                return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
             rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
         }
         if (!NT_SUCCESS(rcNt))
         {
             RTMemFree(pbBuf);
-            return RTErrConvertFromNtStatus(rcNt);
+            return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
+                                 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
         }
     }
 
@@ -3159,7 +3703,7 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
         SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
         if (pHandleInfo->Object == pProtectedProcess)
         {
-            /* Handles within the protected process is fine. */
+            /* Handles within the protected process are fine. */
             if (   !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
                 || pHandleInfo->UniqueProcessId == hProtectedPid)
             {
@@ -3176,10 +3720,11 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
                 continue;
             }
 
-            /* The system process is allowed having one open process handle in
-               Windows 8.1 and later. */
-            if (   g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
-                && cSystemProcessHandles < 1
+            /* The system process is allowed having two open process handle in
+               Windows 8.1 and later, and one in earlier. This is probably a
+               little overly paranoid as I think we can safely trust the
+               system process... */
+            if (   cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? 2 : 1)
                 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
             {
                 cSystemProcessHandles++;
@@ -3243,7 +3788,24 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
             LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
                     pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
                     pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
-            rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+            rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
+                               *pErrInfo->pszMsg
+                               ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
+                               : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
+                               pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
+                               pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
+
+            /* Try add the process name. */
+            PEPROCESS pOffendingProcess;
+            rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
+            if (NT_SUCCESS(rcNt))
+            {
+                const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
+                if (pszName && *pszName)
+                    rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
+
+                ObDereferenceObject(pOffendingProcess);
+            }
         }
     }
 
@@ -3268,30 +3830,39 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
      * on VM processes.
      */
     int rc = VINF_SUCCESS;
-    if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
-        rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect);
+    PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
     if (RT_SUCCESS(rc))
     {
-        char szErr[256];
-        RT_ZERO(szErr);
+        pErrorInfo->hProcessId = PsGetCurrentProcessId();
+        pErrorInfo->hThreadId  = PsGetCurrentThreadId();
         RTERRINFO ErrInfo;
-        RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
+        RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
 
-        rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY,
-                                         NULL /*pcFixes*/, &ErrInfo);
-        if (RT_FAILURE(rc))
-            RTLogWriteDebugger(szErr, strlen(szErr));
+        if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+            rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
+        if (RT_SUCCESS(rc))
+        {
+            rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
+                                             NULL /*pcFixes*/, &ErrInfo);
+            if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+                rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
+        }
     }
+    else
+        rc = VERR_NO_MEMORY;
 
     /*
      * Upgrade and return.
      */
+    HANDLE hOpenTid = PsGetCurrentThreadId();
     RTSpinlockAcquire(g_hNtProtectLock);
 
     /* Stub process verficiation is pretty much straight forward. */
     if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
+    {
         pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
-
+        pNtProtect->hOpenTid       = hOpenTid;
+    }
     /* The VM process verification is a little bit more complicated
        because we need to drop the parent process reference as well. */
     else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
@@ -3307,7 +3878,10 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
         ASMAtomicDecU32(&pNtProtect->cRefs);
 
         if (RT_SUCCESS(rc))
+        {
             pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
+            pNtProtect->hOpenTid       = hOpenTid;
+        }
         else
             pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
     }
@@ -3334,6 +3908,44 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
     }
 
     RTSpinlockRelease(g_hNtProtectLock);
+
+    /*
+     * Free error info on success, keep it on failure.
+     */
+    if (RT_SUCCESS(rc))
+        RTMemFree(pErrorInfo);
+    else if (pErrorInfo)
+    {
+        pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
+        if (!pErrorInfo->cchErrorInfo)
+            pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
+                                                             "supdrvNtProtectVerifyProcess: rc=%d", rc);
+        if (RT_FAILURE(rc))
+            RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
+
+        int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+        if (RT_SUCCESS(rc2))
+        {
+            pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
+
+            /* Free old entries. */
+            PSUPDRVNTERRORINFO pCur;
+            while (   (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
+                   && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
+            {
+                RTListNodeRemove(&pCur->ListEntry);
+                RTMemFree(pCur);
+            }
+
+            /* Insert our new entry. */
+            RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
+
+            RTSemMutexRelease(g_hErrorInfoLock);
+        }
+        else
+            RTMemFree(pErrorInfo);
+    }
+
     return rc;
 }
 
@@ -3384,6 +3996,16 @@ static void supdrvNtProtectTerm(void)
     RTSpinlockDestroy(g_hNtProtectLock);
     g_NtProtectTree = NIL_RTSPINLOCK;
 
+    RTSemMutexDestroy(g_hErrorInfoLock);
+    g_hErrorInfoLock = NIL_RTSEMMUTEX;
+
+    PSUPDRVNTERRORINFO pCur;
+    while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
+    {
+        RTListNodeRemove(&pCur->ListEntry);
+        RTMemFree(pCur);
+    }
+
     supHardenedWinTermImageVerifier();
 }
 
@@ -3432,6 +4054,9 @@ static NTSTATUS supdrvNtProtectInit(void)
     /* Resolve methods we want but isn't available everywhere. */
     UNICODE_STRING RoutineName;
 
+    RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
+    g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
+
     RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
     g_pfnObRegisterCallbacks   = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
 
@@ -3447,6 +4072,9 @@ static NTSTATUS supdrvNtProtectInit(void)
     RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
     g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
 
+    RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
+    g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
+
     RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
     g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
     if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
@@ -3527,6 +4155,18 @@ static NTSTATUS supdrvNtProtectInit(void)
         return STATUS_PROCEDURE_NOT_FOUND;
     }
 
+# ifdef VBOX_STRICT
+    if (   g_uNtVerCombined >= SUP_NT_VER_W70
+        && (   g_pfnObGetObjectType == NULL
+            || g_pfnZwAlpcCreatePort == NULL) )
+    {
+        LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
+        return STATUS_PROCEDURE_NOT_FOUND;
+    }
+# endif
+
+    /* LPC object type. */
+    g_pAlpcPortObjectType1 = *LpcPortObjectType;
 
     /* The spinlock protecting our structures. */
     int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
@@ -3534,119 +4174,131 @@ static NTSTATUS supdrvNtProtectInit(void)
         return VBoxDrvNtErr2NtStatus(rc);
     g_NtProtectTree = NULL;
 
-    /* Image stuff + certificates. */
     NTSTATUS rcNt;
-    rc = supHardenedWinInitImageVerifier(NULL);
+
+    /* The mutex protecting the error information. */
+    RTListInit(&g_ErrorInfoHead);
+    rc = RTSemMutexCreate(&g_hErrorInfoLock);
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Intercept process creation and termination.
-         */
-        if (g_pfnPsSetCreateProcessNotifyRoutineEx)
-            rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
-        else
-            rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
-        if (NT_SUCCESS(rcNt))
+        /* Image stuff + certificates. */
+        rc = supHardenedWinInitImageVerifier(NULL);
+        if (RT_SUCCESS(rc))
         {
             /*
-             * Intercept process and thread handle creation calls.
-             * The preferred method is only available on Vista SP1+.
+             * Intercept process creation and termination.
              */
-            if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
+            if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+                rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
+            else
+                rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
+            if (NT_SUCCESS(rcNt))
             {
-                static OB_OPERATION_REGISTRATION s_aObOperations[] =
+                /*
+                 * Intercept process and thread handle creation calls.
+                 * The preferred method is only available on Vista SP1+.
+                 */
+                if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
                 {
+                    static OB_OPERATION_REGISTRATION s_aObOperations[] =
                     {
-                        PsProcessType,
-                        OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
-                        supdrvNtProtectCallback_ProcessHandlePre,
-                        supdrvNtProtectCallback_ProcessHandlePost,
-                    },
+                        {
+                            PsProcessType,
+                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+                            supdrvNtProtectCallback_ProcessHandlePre,
+                            supdrvNtProtectCallback_ProcessHandlePost,
+                        },
+                        {
+                            PsThreadType,
+                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+                            supdrvNtProtectCallback_ThreadHandlePre,
+                            supdrvNtProtectCallback_ThreadHandlePost,
+                        },
+                    };
+                    static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
                     {
-                        PsThreadType,
-                        OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
-                        supdrvNtProtectCallback_ThreadHandlePre,
-                        supdrvNtProtectCallback_ThreadHandlePost,
-                    },
-                };
-                static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
-                {
-                    /* .Version                     = */ OB_FLT_REGISTRATION_VERSION,
-                    /* .OperationRegistrationCount  = */ RT_ELEMENTS(s_aObOperations),
-                    /* .Altitude.Length             = */ 0,
-                    /* .Altitude.MaximumLength      = */ 0,
-                    /* .Altitude.Buffer             = */ NULL,
-                    /* .RegistrationContext         = */ NULL,
-                    /* .OperationRegistration       = */ &s_aObOperations[0]
-                };
-                static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
-                {
-                     L"48596.98940",  L"46935.19485",  L"49739.39704",  L"40334.74976",
-                     L"66667.98940",  L"69888.19485",  L"69889.39704",  L"60364.74976",
-                     L"85780.98940",  L"88978.19485",  L"89939.39704",  L"80320.74976",
-                     L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
-                };
-
-                rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
-                for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
-                {
-                    s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
-                    s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
-                    s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
-
-                    rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
-                    if (NT_SUCCESS(rcNt))
+                        /* .Version                     = */ OB_FLT_REGISTRATION_VERSION,
+                        /* .OperationRegistrationCount  = */ RT_ELEMENTS(s_aObOperations),
+                        /* .Altitude.Length             = */ 0,
+                        /* .Altitude.MaximumLength      = */ 0,
+                        /* .Altitude.Buffer             = */ NULL,
+                        /* .RegistrationContext         = */ NULL,
+                        /* .OperationRegistration       = */ &s_aObOperations[0]
+                    };
+                    static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
                     {
-                        /*
-                         * Happy ending.
-                         */
-                        return STATUS_SUCCESS;
+                         L"48596.98940",  L"46935.19485",  L"49739.39704",  L"40334.74976",
+                         L"66667.98940",  L"69888.19485",  L"69889.39704",  L"60364.74976",
+                         L"85780.98940",  L"88978.19485",  L"89939.39704",  L"80320.74976",
+                         L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
+                    };
+
+                    rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
+                    for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
+                    {
+                        s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
+                        s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
+                        s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
+
+                        rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
+                        if (NT_SUCCESS(rcNt))
+                        {
+                            /*
+                             * Happy ending.
+                             */
+                            return STATUS_SUCCESS;
+                        }
                     }
+                    LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
+                    g_pvObCallbacksCookie = NULL;
                 }
-                LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
-                g_pvObCallbacksCookie = NULL;
-            }
-            else
-            {
-                /*
-                 * For the time being, we do not implement extra process
-                 * protection on pre-Vista-SP1 systems as they are lacking
-                 * necessary KPIs.  XP is end of life, we do not wish to
-                 * spend more time on it, so we don't put up a fuss there.
-                 * Vista users without SP1 can install SP1 (or later), darn it,
-                 * so refuse to load.
-                 */
-                /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
-                 *        stuff to a couple of object types. */
+                else
+                {
+                    /*
+                     * For the time being, we do not implement extra process
+                     * protection on pre-Vista-SP1 systems as they are lacking
+                     * necessary KPIs.  XP is end of life, we do not wish to
+                     * spend more time on it, so we don't put up a fuss there.
+                     * Vista users without SP1 can install SP1 (or later), darn it,
+                     * so refuse to load.
+                     */
+                    /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
+                     *        stuff to a couple of object types. */
 # ifndef VBOX_WITH_VISTA_NO_SP
-                if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
+                    if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
 # else
-                if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
+                    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
 # endif
-                {
-                    DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
-                    rcNt = STATUS_SXS_VERSION_CONFLICT;
+                    {
+                        DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
+                        rcNt = STATUS_SXS_VERSION_CONFLICT;
+                    }
+                    else
+                    {
+                        Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
+                        return rcNt = STATUS_SUCCESS;
+                    }
+                    g_pvObCallbacksCookie = NULL;
                 }
+
+                /*
+                 * Drop process create/term notifications.
+                 */
+                if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+                    g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
                 else
-                {
-                    Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
-                    return rcNt = STATUS_SUCCESS;
-                }
-                g_pvObCallbacksCookie = NULL;
+                    PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
             }
-
-            /*
-             * Drop process create/term notifications.
-             */
-            if (g_pfnPsSetCreateProcessNotifyRoutineEx)
-                g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
             else
-                PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
+                LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
+                        g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
+            supHardenedWinTermImageVerifier();
         }
         else
-            LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
-                    g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
-        supHardenedWinTermImageVerifier();
+            rcNt = VBoxDrvNtErr2NtStatus(rc);
+
+        RTSemMutexDestroy(g_hErrorInfoLock);
+        g_hErrorInfoLock = NIL_RTSEMMUTEX;
     }
     else
         rcNt = VBoxDrvNtErr2NtStatus(rc);
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h b/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
index 8f9966b..c20055e 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerify-win.h
@@ -53,8 +53,29 @@ typedef enum SUPHARDNTVPKIND
     SUPHARDNTVPKIND_SELF_PURIFICATION,
     SUPHARDNTVPKIND_32BIT_HACK = 0x7fffffff
 } SUPHARDNTVPKIND;
-DECLHIDDEN(int)     supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind,
+/** @name SUPHARDNTVP_F_XXX - Flags for supHardenedWinVerifyProcess
+ * @{ */
+/** Replace unwanted executable memory allocations with a new one that's filled
+ * with a safe read-write copy (default is just to free it).
+ *
+ * This is one way we attempt to work around buggy protection software that
+ * either result in host BSOD or VBox application malfunction.  Here the current
+ * shit list:
+ *  - Trend Micro's data protection software includes a buggy driver called
+ *    sakfile.sys that has been observed crashing accessing user memory that we
+ *    probably freed.  I'd love to report this to Trend Micro, but unfortunately
+ *    they doesn't advertise (or have?) an email address for reporting security
+ *    vulnerabilities in the their software.  Having wasted time looking and not
+ *    very sorry for having to disclosing the bug here.
+ *  - Maybe one more.
+ */
+#define SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW        RT_BIT_32(0)
+/** @} */
+DECLHIDDEN(int)     supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, uint32_t fFlags,
                                                 uint32_t *pcFixes, PRTERRINFO pErrInfo);
+DECLHIDDEN(int)     supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo);
+DECLHIDDEN(int)     supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo);
+
 
 DECLHIDDEN(bool)    supHardViUtf16PathIsEqualEx(PCRTUTF16 pawcLeft, size_t cwcLeft, const char *pszRight);
 DECLHIDDEN(bool)    supHardViUniStrPathStartsWithUniStr(UNICODE_STRING const *pUniStrLeft,
@@ -71,8 +92,11 @@ typedef struct SUPHNTVIRDR
 {
     /** The core reader structure. */
     RTLDRREADER Core;
-    /** The file handle . */
+    /** The file handle. */
     HANDLE      hFile;
+    /** Handle to event sempahore in case we're force to deal with asynchronous
+     * I/O. */
+    HANDLE      hEvent;
     /** Current file offset. */
     RTFOFF      off;
     /** The file size. */
@@ -137,12 +161,17 @@ typedef struct SUPHNTLDRCACHEENTRY
     uint8_t            *pbBits;
     /** Set if verified. */
     bool                fVerified;
+    /** Whether we've got valid cacheable image bit.s */
+    bool                fValidBits;
+    /** The image base address. */
+    uintptr_t           uImageBase;
 } SUPHNTLDRCACHEENTRY;
 /** Pointer to a loader cache entry. */
 typedef SUPHNTLDRCACHEENTRY *PSUPHNTLDRCACHEENTRY;
 DECLHIDDEN(int)  supHardNtLdrCacheOpen(const char *pszName, PSUPHNTLDRCACHEENTRY *ppEntry);
 DECLHIDDEN(int)  supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUTF16 pwszName, PRTERRINFO pErrInfo);
-DECLHIDDEN(int)  supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, PRTERRINFO pErrInfo);
+DECLHIDDEN(int)  supHardNtLdrCacheEntryGetBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, RTLDRADDR uBaseAddress,
+                                               PFNRTLDRIMPORT pfnGetImport, void *pvUser, PRTERRINFO pErrInfo);
 
 
 /** Which directory under the system root to get. */
@@ -164,14 +193,14 @@ typedef struct SUPSYSROOTDIRBUF
 } SUPSYSROOTDIRBUF;
 extern SUPSYSROOTDIRBUF g_System32NtPath;
 extern SUPSYSROOTDIRBUF g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 extern SUPSYSROOTDIRBUF g_ProgramFilesNtPath;
 extern SUPSYSROOTDIRBUF g_CommonFilesNtPath;
 # if ARCH_BITS == 64
 extern SUPSYSROOTDIRBUF g_ProgramFilesX86NtPath;
 extern SUPSYSROOTDIRBUF g_CommonFilesX86NtPath;
 # endif
-#endif
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
 extern SUPSYSROOTDIRBUF g_SupLibHardenedExeNtPath;
 extern uint32_t         g_offSupLibHardenedExeNtName;
 
@@ -194,18 +223,23 @@ extern PFNNTQUERYVIRTUALMEMORY g_pfnNtQueryVirtualMemory;
 #define SUP_MAKE_NT_VER_SIMPLE(a_uMajor, a_uMinor) SUP_MAKE_NT_VER_COMBINED(a_uMajor, a_uMinor, 0, 0, 0)
 extern uint32_t         g_uNtVerCombined;
 
+/** @name NT version constants for less-than checks.
+ * @{ */
 /** Combined NT version number for XP. */
 #define SUP_NT_VER_XP       SUP_MAKE_NT_VER_SIMPLE(5,1)
 /** Combined NT version number for Windows server 2003 & XP64. */
 #define SUP_NT_VER_W2K3     SUP_MAKE_NT_VER_SIMPLE(5,2)
 /** Combined NT version number for Vista. */
 #define SUP_NT_VER_VISTA    SUP_MAKE_NT_VER_SIMPLE(6,0)
+/** Combined NT version number for Vista with SP1. */
+#define SUP_NT_VER_VISTA_SP1 SUP_MAKE_NT_VER_COMBINED(6,0,6001,1,0)
 /** Combined NT version number for Windows 7. */
 #define SUP_NT_VER_W70      SUP_MAKE_NT_VER_SIMPLE(6,1)
 /** Combined NT version number for Windows 8.0. */
 #define SUP_NT_VER_W80      SUP_MAKE_NT_VER_SIMPLE(6,2)
 /** Combined NT version number for Windows 8.1. */
 #define SUP_NT_VER_W81      SUP_MAKE_NT_VER_SIMPLE(6,3)
+/** @} */
 
 # endif
 
@@ -213,9 +247,6 @@ extern uint32_t         g_uNtVerCombined;
 #  include <iprt/mem.h>
 #  include <iprt/string.h>
 
-#  define suplibHardenedAllocZ       RTMemAllocZ
-#  define suplibHardenedReAlloc      RTMemRealloc
-#  define suplibHardenedFree         RTMemFree
 #  define suplibHardenedMemComp      memcmp
 #  define suplibHardenedMemCopy      memcpy
 #  define suplibHardenedMemSet       memset
@@ -226,7 +257,7 @@ extern uint32_t         g_uNtVerCombined;
 #  define suplibHardenedStrNCmp      strncmp
 # else   /* IN_SUP_HARDENED_R3 */
 #  include <iprt/mem.h>
-#if 0
+#  if 0
 #  define memcmp                     suplibHardenedMemComp
 #  define memcpy                     suplibHardenedMemCopy
 #  define memset                     suplibHardenedMemSet
@@ -235,10 +266,7 @@ extern uint32_t         g_uNtVerCombined;
 #  define strcat                     suplibHardenedStrCat
 #  define strcmp                     suplibHardenedStrCmp
 #  define strncmp                    suplibHardenedStrNCmp
-#endif
-DECLHIDDEN(void *)  suplibHardenedAllocZ(size_t cb);
-DECLHIDDEN(void *)  suplibHardenedReAlloc(void *pvOld, size_t cbNew);
-DECLHIDDEN(void)    suplibHardenedFree(void *pv);
+#  endif
 # endif  /* IN_SUP_HARDENED_R3 */
 
 #endif /* SUP_CERTIFICATES_ONLY */
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
index ac45b58..d7656b3 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
@@ -121,7 +121,7 @@ static RTCRSTORE            g_hSpcAndNtKernelSuppStore = NIL_RTCRSTORE;
 SUPSYSROOTDIRBUF            g_System32NtPath;
 /** The full \\SystemRoot\\WinSxS path. */
 SUPSYSROOTDIRBUF            g_WinSxSNtPath;
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 /** The full 'Program Files' path. */
 SUPSYSROOTDIRBUF            g_ProgramFilesNtPath;
 # ifdef RT_ARCH_AMD64
@@ -134,7 +134,7 @@ SUPSYSROOTDIRBUF            g_CommonFilesNtPath;
 /** The full 'Common Files (x86)' path. */
 SUPSYSROOTDIRBUF            g_CommonFilesX86NtPath;
 # endif
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_MORE*/
 
 static union
 {
@@ -144,7 +144,9 @@ static union
 /** The TrustedInstaller SID (Vista+). */
                             g_TrustedInstallerSid,
 /** Local system ID (S-1-5-21). */
-                            g_LocalSystemSid;
+                            g_LocalSystemSid,
+/** Builtin Administrators group alias (S-1-5-32-544). */
+                            g_AdminsGroupSid;
 
 
 /** Set after we've retrived other SPC root certificates from the system. */
@@ -208,93 +210,67 @@ static DECLCALLBACK(int) supHardNtViRdrRead(PRTLDRREADER pReader, void *pvBuf, s
 {
     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)pReader;
     Assert(pNtViRdr->Core.uMagic == RTLDRREADER_MAGIC);
+    NTSTATUS rcNt;
 
+    /* Check for type overflow (paranoia). */
     if ((ULONG)cb != cb)
         return VERR_OUT_OF_RANGE;
 
-
-    /*
-     * For some reason I'm getting occational read error in an XP VM with
-     * STATUS_FAILED_DRIVER_ENTRY.  Redoing the call again works in the
-     * debugger, so try do that automatically.
-     */
-    for (uint32_t iTry = 0;; iTry++)
-    {
-        LARGE_INTEGER offNt;
-        offNt.QuadPart = off;
-
-        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-        NTSTATUS rcNt = NtReadFile(pNtViRdr->hFile,
-                                   NULL /*hEvent*/,
-                                   NULL /*ApcRoutine*/,
-                                   NULL /*ApcContext*/,
-                                   &Ios,
-                                   pvBuf,
-                                   (ULONG)cb,
-                                   &offNt,
-                                   NULL);
-        if (NT_SUCCESS(rcNt))
-            rcNt = Ios.Status;
-        if (NT_SUCCESS(rcNt))
-        {
-            if (Ios.Information == cb)
-            {
-                pNtViRdr->off = off + cb;
-                return VINF_SUCCESS;
-            }
 #ifdef IN_RING3
-            supR3HardenedError(VERR_READ_ERROR, false,
-                               "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
-                               Ios.Information, off, cb, pNtViRdr->szFilename);
+    /* Make sure the event semaphore is reset (normally we don't use one). */
+    if (pNtViRdr->hEvent)
+    {
+        rcNt = NtClearEvent(pNtViRdr->hEvent);
+        if (!NT_SUCCESS(rcNt))
+            return RTErrConvertFromNtStatus(rcNt);
+    }
 #endif
-            pNtViRdr->off = -1;
-            return VERR_READ_ERROR;
-        }
 
-        /*
-         * Delay a little before we retry?
-         */
-#ifdef IN_RING3
-        if (iTry == 0)
-            NtYieldExecution();
-        else if (iTry >= 1)
-        {
-            LARGE_INTEGER Time;
-            Time.QuadPart = -1000000 / 100; /* 1ms in 100ns units, relative time. */
-            NtDelayExecution(TRUE, &Time);
-        }
+    /* Perform the read. */
+    LARGE_INTEGER offNt;
+    offNt.QuadPart = off;
+
+    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+    rcNt = NtReadFile(pNtViRdr->hFile,
+                      pNtViRdr->hEvent,
+                      NULL /*ApcRoutine*/,
+                      NULL /*ApcContext*/,
+                      &Ios,
+                      pvBuf,
+                      (ULONG)cb,
+                      &offNt,
+                      NULL);
+
+#ifdef IN_RING0
+    /* In ring-0 the handles shall be synchronized and not alertable. */
+    AssertMsg(rcNt == STATUS_SUCCESS || !NT_SUCCESS(rcNt), ("%#x\n", rcNt));
+#else
+    /* In ring-3 we like our handles synchronized and non-alertable, but we
+       sometimes have to take what we can get.  So, deal with pending I/O as
+       best we can. */
+    if (rcNt == STATUS_PENDING)
+        rcNt = NtWaitForSingleObject(pNtViRdr->hEvent ? pNtViRdr->hEvent : pNtViRdr->hFile, FALSE /*Alertable*/, NULL);
 #endif
-        /*
-         * Before we give up, we'll try split up the request in case the
-         * kernel is low on memory or similar.  For simplicity reasons, we do
-         * this in a recursion fashion.
-         */
-        if (iTry >= 2)
+    if (NT_SUCCESS(rcNt))
+        rcNt = Ios.Status;
+    if (NT_SUCCESS(rcNt))
+    {
+        /* We require the caller to not read beyond the end of the file since
+           we don't have any way to communicate that we've read less that
+           requested. */
+        if (Ios.Information == cb)
         {
-            if (cb >= _8K)
-            {
-                size_t const cbBlock = RT_ALIGN_Z(cb / 4, 512);
-                while (cb > 0)
-                {
-                    size_t cbThisRead = RT_MIN(cb, cbBlock);
-                    int rc = supHardNtViRdrRead(&pNtViRdr->Core, pvBuf, cbThisRead, off);
-                    if (RT_FAILURE(rc))
-                        return rc;
-                    off  += cbThisRead;
-                    cb   -= cbThisRead;
-                    pvBuf = (uint8_t *)pvBuf + cbThisRead;
-                }
-                return VINF_SUCCESS;
-            }
-
+            pNtViRdr->off = off + cb; /* (just for show) */
+            return VINF_SUCCESS;
+        }
 #ifdef IN_RING3
-            supR3HardenedError(VERR_READ_ERROR, false, "supHardNtViRdrRead: Error %#x reading %#zx bytes at %#llx in '%s'.\n",
-                               rcNt, off, cb, pNtViRdr->szFilename);
+        supR3HardenedError(VERR_READ_ERROR, false,
+                           "supHardNtViRdrRead: Only got %#zx bytes when requesting %#zx bytes at %#llx in '%s'.\n",
+                           Ios.Information, off, cb, pNtViRdr->szFilename);
 #endif
-            pNtViRdr->off = -1;
-            return VERR_READ_ERROR;
-        }
     }
+    pNtViRdr->off = -1;
+    return VERR_READ_ERROR;
 }
 
 
@@ -346,7 +322,13 @@ static DECLCALLBACK(int) supHardNtViRdrDestroy(PRTLDRREADER pReader)
 
     pNtViRdr->Core.uMagic = ~RTLDRREADER_MAGIC;
     pNtViRdr->hFile = NULL;
-
+#ifdef IN_RING3
+    if (pNtViRdr->hEvent)
+    {
+        NtClose(pNtViRdr->hEvent);
+        pNtViRdr->hEvent = NULL;
+    }
+#endif
     RTMemFree(pNtViRdr);
     return VINF_SUCCESS;
 }
@@ -373,6 +355,31 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
         return VERR_LDRVI_FILE_LENGTH_ERROR;
 
     /*
+     * Figure the file mode so we can see whether we'll be needing an event
+     * semaphore for waiting on reads.  This may happen in very unlikely
+     * NtCreateSection scenarios.
+     */
+#if defined(IN_RING3) || defined(VBOX_STRICT)
+    Ios.Status = STATUS_UNSUCCESSFUL;
+    ULONG fMode;
+    rcNt = NtQueryInformationFile(hFile, &Ios, &fMode, sizeof(fMode), FileModeInformation);
+    if (!NT_SUCCESS(rcNt) || !NT_SUCCESS(Ios.Status))
+        return VERR_SUP_VP_FILE_MODE_ERROR;
+#endif
+
+    HANDLE hEvent = NULL;
+#ifdef IN_RING3
+    if (!(fMode & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)))
+    {
+        rcNt = NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
+        if (!NT_SUCCESS(rcNt))
+            return VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED;
+    }
+#else
+    Assert(fMode & FILE_SYNCHRONOUS_IO_NONALERT);
+#endif
+
+    /*
      * Calc the file name length and allocate memory for the reader instance.
      */
     size_t cchFilename = 0;
@@ -382,7 +389,13 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
     int rc = VERR_NO_MEMORY;
     PSUPHNTVIRDR pNtViRdr = (PSUPHNTVIRDR)RTMemAllocZ(sizeof(*pNtViRdr) + cchFilename);
     if (!pNtViRdr)
+    {
+#ifdef IN_RING3
+        if (hEvent != NULL)
+            NtClose(hEvent);
+#endif
         return VERR_NO_MEMORY;
+    }
 
     /*
      * Initialize the structure.
@@ -405,6 +418,7 @@ DECLHIDDEN(int) supHardNtViRdrCreate(HANDLE hFile, PCRTUTF16 pwszName, uint32_t
     pNtViRdr->Core.pfnUnmap   = supHardNtViRdrUnmap;
     pNtViRdr->Core.pfnDestroy = supHardNtViRdrDestroy;
     pNtViRdr->hFile           = hFile;
+    pNtViRdr->hEvent          = hEvent;
     pNtViRdr->off             = 0;
     pNtViRdr->cbFile          = StdInfo.EndOfFile.QuadPart;
     pNtViRdr->fFlags          = fFlags;
@@ -451,9 +465,17 @@ static bool supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(HANDLE hFile, PCR
      * turned up owned by the local system user, and we cannot operate without
      * the plugin loaded once it's installed (WinVerityTrust fails).
      *
-     * Note! We cannot really allow Builtin\Administrators here it's the default
-     *       owner of anything an admin user creates. (We must, unforutnately,
-     *       allow that in system32 though.)
+     * We'd like to avoid allowing Builtin\Administrators here since it's the
+     * default owner of anything an admin user creates (at least when elevated).
+     * Seems windows update or someone ends up installing or modifying system
+     * DLL ownership to this group, so for system32 and winsxs it's unavoidable.
+     * And, not surprise, a bunch of products, including AV, firewalls and similar
+     * ends up with their files installed with this group as owner.  For instance
+     * if we wish to have NAT continue working, we need to allow this.
+     *
+     * Hopefully, we can limit the allowed files to these owners though, so
+     * we won't be subject to ordinary (non-admin, or not elevated) users
+     * downloading or be tricked into putting evil DLLs around the place...
      */
     PSID pOwner = uBuf.Rel.Control & SE_SELF_RELATIVE ? &uBuf.abView[uBuf.Rel.Owner] : uBuf.Abs.Owner;
     Assert((uintptr_t)pOwner - (uintptr_t)&uBuf < sizeof(uBuf) - sizeof(SID));
@@ -461,6 +483,11 @@ static bool supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(HANDLE hFile, PCR
         return true;
     if (RtlEqualSid(pOwner, &g_LocalSystemSid))
         return true;
+    if (RtlEqualSid(pOwner, &g_AdminsGroupSid))
+    {
+        SUP_DPRINTF(("%ls: Owner is administrators group.\n", pwszName));
+        return true;
+    }
 
     SUP_DPRINTF(("%ls: Owner is not trusted installer (%.*Rhxs)\n",
                  pwszName, ((uint8_t *)pOwner)[1] /*SubAuthorityCount*/ * sizeof(ULONG) + 8, pOwner));
@@ -1065,27 +1092,38 @@ DECLHIDDEN(int) supHardenedWinVerifyImageByLdrMod(RTLDRMOD hLdrMod, PCRTUTF16 pw
      * Check the trusted installer bit first, if requested as it's somewhat
      * cheaper than the rest.
      *
-     * We relax this for system32, like we used to, as there are apparently
-     * some systems out there where the user, admin, or someone has changed the
-     * ownership of core windows DLLs like user32.dll.  Since we need user32.dll
-     * and will be checking it's digital signature, it's reasonably safe to let
-     * this thru. (The report was of SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS
+     * We relax this for system32 and a little for WinSxS, like we used to, as
+     * there are apparently  some systems out there where the user, admin, or
+     * someone has changed the ownership of core windows DLLs like user32.dll
+     * and comctl32.dll.  Since we need user32.dll  and will be checking it's
+     * digital signature, it's reasonably safe to let this thru. (The report
+     * was of SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS
      * owning user32.dll, see public ticket 13187, VBoxStartup.3.log.)
      *
      * We've also had problems with graphics driver components like ig75icd64.dll
      * and atig6pxx.dll not being owned by TrustedInstaller, with the result
      * that 3D got broken (mod by zero issue in test build 5).  These were also
      * SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS.
+     *
+     * In one report by 'thor' the WinSxS resident comctl32.dll was owned by
+     * SECURITY_BUILTIN_DOMAIN_RID + DOMAIN_ALIAS_RID_ADMINS (with 4.3.16).
      */
+    /** @todo Since we're now allowing Builtin\Administrators after all, perhaps we
+     *        could drop these system32 + winsxs hacks?? */
     if (   (pNtViRdr->fFlags & SUPHNTVI_F_TRUSTED_INSTALLER_OWNER)
         && !supHardNtViCheckIsOwnedByTrustedInstallerOrSimilar(pNtViRdr->hFile, pwszName))
     {
-        if (!supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
-                                            g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR),
-                                            true /*fCheckSlash*/))
+        if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
+                                           g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR),
+                                           true /*fCheckSlash*/))
+            SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in system32).\n", pwszName));
+        else if (supHardViUtf16PathStartsWithEx(pwszName, (uint32_t)RTUtf16Len(pwszName),
+                                                g_WinSxSNtPath.UniStr.Buffer, g_WinSxSNtPath.UniStr.Length / sizeof(WCHAR),
+                                                true /*fCheckSlash*/))
+            SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in WinSxS).\n", pwszName));
+        else
             return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER,
                                  "supHardenedWinVerifyImageByHandle: TrustedInstaller is not the owner of '%ls'.", pwszName);
-        SUP_DPRINTF(("%ls: Relaxing the TrustedInstaller requirement for this DLL (it's in system32).\n", pwszName));
     }
 
     /*
@@ -1416,8 +1454,7 @@ static int supHardNtViCertStoreInit(PRTCRSTORE phStore,
 }
 
 
-
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
 /**
  * Initializes the windows paths.
  */
@@ -1605,7 +1642,7 @@ static void supHardenedWinInitImageVerifierWinPaths(void)
         }
     }
 }
-#endif /* IN_RING3 */
+#endif /* IN_RING3 && !VBOX_PERMIT_EVEN_MORE */
 
 
 /**
@@ -1629,7 +1666,7 @@ DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
     {
         SUP_DPRINTF(("System32:  %ls\n", g_System32NtPath.UniStr.Buffer));
         SUP_DPRINTF(("WinSxS:    %ls\n", g_WinSxSNtPath.UniStr.Buffer));
-#ifdef IN_RING3
+#if defined(IN_RING3) && !defined(VBOX_PERMIT_EVEN_MORE)
         supHardenedWinInitImageVerifierWinPaths();
 #endif
 
@@ -1681,12 +1718,18 @@ DECLHIDDEN(int) supHardenedWinInitImageVerifier(PRTERRINFO pErrInfo)
                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 4) = 1853292631;
                 *RtlSubAuthoritySid(&g_TrustedInstallerSid, 5) = 2271478464;
 
-                if (NT_SUCCESS(rcNt))
-                    rcNt = RtlInitializeSid(&g_LocalSystemSid, &s_NtAuth, 1);
+                rcNt = RtlInitializeSid(&g_LocalSystemSid, &s_NtAuth, 1);
                 if (NT_SUCCESS(rcNt))
                 {
                     *RtlSubAuthoritySid(&g_LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
-                    return VINF_SUCCESS;
+
+                    rcNt = RtlInitializeSid(&g_AdminsGroupSid, &s_NtAuth, 2);
+                    if (NT_SUCCESS(rcNt))
+                    {
+                        *RtlSubAuthoritySid(&g_AdminsGroupSid, 0) = SECURITY_BUILTIN_DOMAIN_RID;
+                        *RtlSubAuthoritySid(&g_AdminsGroupSid, 1) = DOMAIN_ALIAS_RID_ADMINS;
+                        return VINF_SUCCESS;
+                    }
                 }
             }
             rc = RTErrConvertFromNtStatus(rcNt);
@@ -1878,13 +1921,13 @@ DECLHIDDEN(HMODULE) supR3HardenedWinLoadSystem32Dll(const char *pszName)
     if (   hMod == NULL
         && fFlags
         && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
-        && GetLastError() == ERROR_INVALID_PARAMETER)
+        && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
     {
         fFlags = 0;
         hMod = LoadLibraryExW(wszName, NULL, fFlags);
     }
     if (hMod == NULL)
-        supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, GetLastError(), wszName);
+        supR3HardenedFatal("Error loading '%s': %u [%ls]", pszName, RtlGetLastWin32Error(), wszName);
     return hMod;
 }
 
@@ -1906,7 +1949,7 @@ static void supR3HardenedWinRetrieveTrustedRootCAs(void)
 
 #define RESOLVE_CRYPT32_API(a_Name, a_pfnType) \
     a_pfnType pfn##a_Name = (a_pfnType)GetProcAddress(hCrypt32, #a_Name); \
-    if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", GetLastError())
+    if (pfn##a_Name == NULL) supR3HardenedFatal("Error locating '" #a_Name "' in 'crypt32.dll': %u", RtlGetLastWin32Error())
     RESOLVE_CRYPT32_API(CertOpenStore, PFNCERTOPENSTORE);
     RESOLVE_CRYPT32_API(CertCloseStore, PFNCERTCLOSESTORE);
     RESOLVE_CRYPT32_API(CertEnumCertificatesInStore, PFNCERTENUMCERTIFICATESINSTORE);
@@ -1993,7 +2036,7 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
     suplibHardenedStrCat(szPath, "/VBoxSupLib.DLL");
     HMODULE hSupLibMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, true /*fSystem32Only*/);
     if (hSupLibMod == NULL)
-        supR3HardenedFatal("Error loading '%s': %u", szPath, GetLastError());
+        supR3HardenedFatal("Error loading '%s': %u", szPath, RtlGetLastWin32Error());
 # endif
 
     /*
@@ -2003,7 +2046,7 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
     if (iTls != TLS_OUT_OF_INDEXES)
         g_iTlsWinVerifyTrustRecursion = iTls;
     else
-        supR3HardenedError(GetLastError(), false /*fFatal*/, "TlsAlloc failed");
+        supR3HardenedError(RtlGetLastWin32Error(), false /*fFatal*/, "TlsAlloc failed");
 
     /*
      * Resolve it.
@@ -2013,12 +2056,12 @@ DECLHIDDEN(void) supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(cons
     do { \
         g_pfn##a_Name = (a_pfnType)GetProcAddress(hWintrust, #a_Name); \
         if (g_pfn##a_Name == NULL && (a_uMinWinVer) < g_uNtVerCombined) \
-            supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", GetLastError()); \
+            supR3HardenedFatal("Error locating '" #a_Name "' in 'Wintrust.dll': %u", RtlGetLastWin32Error()); \
     } while (0)
 
     PFNWINVERIFYTRUST pfnWinVerifyTrust = (PFNWINVERIFYTRUST)GetProcAddress(hWintrust, "WinVerifyTrust");
     if (!pfnWinVerifyTrust)
-        supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", GetLastError());
+        supR3HardenedFatal("Error locating 'WinVerifyTrust' in 'Wintrust.dll': %u", RtlGetLastWin32Error());
 
     RESOLVE_CRYPT_API(CryptCATAdminAcquireContext,           PFNCRYPTCATADMINACQUIRECONTEXT,          0);
     RESOLVE_CRYPT_API(CryptCATAdminCalcHashFromFileHandle,   PFNCRYPTCATADMINCALCHASHFROMFILEHANDLE,  0);
@@ -2151,23 +2194,25 @@ static int supR3HardNtViCallWinVerifyTrust(HANDLE hFile, PCRTUTF16 pwszName, uin
         const char *pszErrConst = NULL;
         switch (hrc)
         {
-            case TRUST_E_SYSTEM_ERROR:             pszErrConst = "TRUST_E_SYSTEM_ERROR";          break;
-            case TRUST_E_NO_SIGNER_CERT:           pszErrConst = "TRUST_E_NO_SIGNER_CERT";        break;
-            case TRUST_E_COUNTER_SIGNER:           pszErrConst = "TRUST_E_COUNTER_SIGNER";        break;
-            case TRUST_E_CERT_SIGNATURE:           pszErrConst = "TRUST_E_CERT_SIGNATURE";        break;
-            case TRUST_E_TIME_STAMP:               pszErrConst = "TRUST_E_TIME_STAMP";            break;
-            case TRUST_E_BAD_DIGEST:               pszErrConst = "TRUST_E_BAD_DIGEST";            break;
-            case TRUST_E_BASIC_CONSTRAINTS:        pszErrConst = "TRUST_E_BASIC_CONSTRAINTS";     break;
-            case TRUST_E_FINANCIAL_CRITERIA:       pszErrConst = "TRUST_E_FINANCIAL_CRITERIA";    break;
-            case TRUST_E_PROVIDER_UNKNOWN:         pszErrConst = "TRUST_E_PROVIDER_UNKNOWN";      break;
-            case TRUST_E_ACTION_UNKNOWN:           pszErrConst = "TRUST_E_ACTION_UNKNOWN";        break;
-            case TRUST_E_SUBJECT_FORM_UNKNOWN:     pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN";  break;
-            case TRUST_E_SUBJECT_NOT_TRUSTED:      pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED";   break;
-            case TRUST_E_NOSIGNATURE:              pszErrConst = "TRUST_E_NOSIGNATURE";           break;
-            case TRUST_E_FAIL:                     pszErrConst = "TRUST_E_FAIL";                  break;
-            case TRUST_E_EXPLICIT_DISTRUST:        pszErrConst = "TRUST_E_EXPLICIT_DISTRUST";     break;
-            case CERT_E_CHAINING:                  pszErrConst = "CERT_E_CHAINING";               break;
-            case CERT_E_REVOCATION_FAILURE:        pszErrConst = "CERT_E_REVOCATION_FAILURE";     break;
+            case TRUST_E_SYSTEM_ERROR:            pszErrConst = "TRUST_E_SYSTEM_ERROR";         break;
+            case TRUST_E_NO_SIGNER_CERT:          pszErrConst = "TRUST_E_NO_SIGNER_CERT";       break;
+            case TRUST_E_COUNTER_SIGNER:          pszErrConst = "TRUST_E_COUNTER_SIGNER";       break;
+            case TRUST_E_CERT_SIGNATURE:          pszErrConst = "TRUST_E_CERT_SIGNATURE";       break;
+            case TRUST_E_TIME_STAMP:              pszErrConst = "TRUST_E_TIME_STAMP";           break;
+            case TRUST_E_BAD_DIGEST:              pszErrConst = "TRUST_E_BAD_DIGEST";           break;
+            case TRUST_E_BASIC_CONSTRAINTS:       pszErrConst = "TRUST_E_BASIC_CONSTRAINTS";    break;
+            case TRUST_E_FINANCIAL_CRITERIA:      pszErrConst = "TRUST_E_FINANCIAL_CRITERIA";   break;
+            case TRUST_E_PROVIDER_UNKNOWN:        pszErrConst = "TRUST_E_PROVIDER_UNKNOWN";     break;
+            case TRUST_E_ACTION_UNKNOWN:          pszErrConst = "TRUST_E_ACTION_UNKNOWN";       break;
+            case TRUST_E_SUBJECT_FORM_UNKNOWN:    pszErrConst = "TRUST_E_SUBJECT_FORM_UNKNOWN"; break;
+            case TRUST_E_SUBJECT_NOT_TRUSTED:     pszErrConst = "TRUST_E_SUBJECT_NOT_TRUSTED";  break;
+            case TRUST_E_NOSIGNATURE:             pszErrConst = "TRUST_E_NOSIGNATURE";          break;
+            case TRUST_E_FAIL:                    pszErrConst = "TRUST_E_FAIL";                 break;
+            case TRUST_E_EXPLICIT_DISTRUST:       pszErrConst = "TRUST_E_EXPLICIT_DISTRUST";    break;
+            case CERT_E_CHAINING:                 pszErrConst = "CERT_E_CHAINING";              break;
+            case CERT_E_REVOCATION_FAILURE:       pszErrConst = "CERT_E_REVOCATION_FAILURE";    break;
+            case CRYPT_E_FILE_ERROR:              pszErrConst = "CRYPT_E_FILE_ERROR";           break;
+            case CRYPT_E_REVOKED:                 pszErrConst = "CRYPT_E_REVOKED";              break;
         }
         if (pszErrConst)
             rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_UNSUPPORTED_ARCH,
@@ -2253,6 +2298,7 @@ static int supR3HardNtViCallWinVerifyTrustCatFile(HANDLE hFile, PCRTUTF16 pwszNa
     /*
      * On Windows 8.0 and later there are more than one digest choice.
      */
+    int fNoSignedCatalogFound = -1;
     rc = VERR_LDRVI_NOT_SIGNED;
     static struct
     {
@@ -2339,16 +2385,21 @@ l_fresh_context:
                             {
                                 if (!fFreshContext)
                                 {
-                                    SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", GetLastError(), iCat));
+                                    SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: Retrying with fresh context (CryptCATAdminEnumCatalogFromHash -> %u; iCat=%#x)\n", RtlGetLastWin32Error(), iCat));
                                     if (hCatInfoPrev != NULL)
                                         g_pfnCryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfoPrev, 0 /*dwFlags*/);
                                     g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/);
                                     goto l_fresh_context;
                                 }
+                                ULONG ulErr = RtlGetLastWin32Error();
+                                fNoSignedCatalogFound = ulErr == ERROR_NOT_FOUND && fNoSignedCatalogFound != 0;
                                 if (iCat == 0)
-                                    SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", GetLastError()));
+                                    SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed ERRROR_NOT_FOUND (%u)\n", ulErr));
+                                else if (iCat == 0)
+                                    SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATAdminEnumCatalogFromHash failed %u\n", ulErr));
                                 break;
                             }
+                            fNoSignedCatalogFound = 0;
                             Assert(hCatInfoPrev == NULL);
                             hCatInfoPrev = hCatInfo;
 
@@ -2410,9 +2461,9 @@ l_fresh_context:
                             }
                             else
                             {
-                                rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
+                                rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
                                                    "CryptCATCatalogInfoFromContext failed: %d [file=%s]",
-                                                   GetLastError(), pwszName);
+                                                   RtlGetLastWin32Error(), pwszName);
                                 SUP_DPRINTF(("supR3HardNtViCallWinVerifyTrustCatFile: CryptCATCatalogInfoFromContext failed\n"));
                             }
                             iCat++;
@@ -2426,16 +2477,16 @@ l_fresh_context:
                         rc = RTErrInfoSetF(pErrInfo, rc2, "RTUtf16PrintHexBytes failed: %Rrc", rc);
                 }
                 else
-                    rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
-                                       "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", GetLastError(), pwszName);
+                    rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+                                       "CryptCATAdminCalcHashFromFileHandle[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
 
                 if (!ASMAtomicCmpXchgPtr(&s_aHashes[i].hCachedCatAdmin, hCatAdmin, NULL))
                     if (!g_pfnCryptCATAdminReleaseContext(hCatAdmin, 0 /*dwFlags*/))
                         AssertFailed();
             }
             else
-                rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(GetLastError()),
-                                   "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", GetLastError(), pwszName);
+                rc = RTErrInfoSetF(pErrInfo, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+                                   "CryptCATAdminAcquireContext[2] failed: %d [file=%s]", RtlGetLastWin32Error(), pwszName);
              iPolicy++;
         } while (   fTryNextPolicy
                  && iPolicy < RT_ELEMENTS(s_aPolicies));
@@ -2452,6 +2503,45 @@ l_fresh_context:
     if (hFileClose != NULL)
         NtClose(hFileClose);
 
+    /*
+     * DLLs that are likely candidates for local modifications.
+     */
+    if (rc == VERR_LDRVI_NOT_SIGNED)
+    {
+        bool        fCoreSystemDll = false;
+        PCRTUTF16   pwsz;
+        uint32_t    cwcName  = (uint32_t)RTUtf16Len(pwszName);
+        uint32_t    cwcOther = g_System32NtPath.UniStr.Length / sizeof(WCHAR);
+        if (supHardViUtf16PathStartsWithEx(pwszName, cwcName, g_System32NtPath.UniStr.Buffer, cwcOther, true /*fCheckSlash*/))
+        {
+            pwsz = pwszName + cwcOther + 1;
+            if (   supHardViUtf16PathIsEqual(pwsz, "uxtheme.dll")
+                || supHardViUtf16PathIsEqual(pwsz, "user32.dll")
+                || supHardViUtf16PathIsEqual(pwsz, "gdi32.dll")
+                || supHardViUtf16PathIsEqual(pwsz, "opengl32.dll")
+                || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "KernelBase.dll"))
+                || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "kernel32.dll"))
+                || (fCoreSystemDll = supHardViUtf16PathIsEqual(pwsz, "ntdll.dll"))
+                )
+            {
+                if (RTErrInfoIsSet(pErrInfo))
+                    RTErrInfoAdd(pErrInfo, rc, "\n");
+                RTErrInfoAddF(pErrInfo, rc, "'%ls' is most likely modified.", pwszName);
+            }
+        }
+
+        /* Kludge for ancient windows versions we don't want to support but
+           users still wants to use.  Keep things as safe as possible without
+           unnecessary effort.  Problem is that 3rd party catalog files cannot
+           easily be found.  Showstopper for ATI users. */
+        if (   fNoSignedCatalogFound == 1
+            && g_uNtVerCombined < SUP_NT_VER_VISTA
+            && !fCoreSystemDll)
+        {
+            rc = VINF_LDRVI_NOT_SIGNED;
+        }
+    }
+
     return rc;
 }
 
@@ -2493,7 +2583,7 @@ DECLHIDDEN(int) supHardenedWinVerifyImageTrust(HANDLE hFile, PCRTUTF16 pwszName,
         }
         else
         {
-            uint32_t const idCurrentThread = GetCurrentThreadId();
+            uint32_t const idCurrentThread = RTNtCurrentThreadId();
             fNoRecursion = ASMAtomicCmpXchgU32(&g_idActiveThread, idCurrentThread, UINT32_MAX);
         }
         if (fNoRecursion)
@@ -2557,7 +2647,7 @@ DECLHIDDEN(bool) supHardenedWinIsWinVerifyTrustCallable(void)
     return g_pfnWinVerifyTrust != NULL
         && (   g_iTlsWinVerifyTrustRecursion != UINT32_MAX
             ?  (uintptr_t)TlsGetValue(g_iTlsWinVerifyTrustRecursion) == 0
-            : g_idActiveThread != GetCurrentThreadId() );
+            : g_idActiveThread != RTNtCurrentThreadId() );
 }
 
 
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
index 6312896..4d7c91c 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp
@@ -128,6 +128,8 @@ typedef struct SUPHNTVPSTATE
 {
     /** Type of verification to perform. */
     SUPHARDNTVPKIND         enmKind;
+    /** Combination of SUPHARDNTVP_F_XXX. */
+    uint32_t                fFlags;
     /** The result. */
     int                     rcResult;
     /** Number of fixes we've done.
@@ -809,15 +811,14 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
      * Get relocated bits.
      */
     uint8_t *pbBits;
-    rc = supHardNtLdrCacheEntryAllocBits(pImage->pCacheEntry, &pbBits, pThis->pErrInfo);
-    if (RT_FAILURE(rc))
-        return rc;
     if (pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
-        rc = RTLdrGetBits(pImage->pCacheEntry->hLdrMod, pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis);
+        rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, NULL /*pfnGetImport*/, pThis,
+                                           pThis->pErrInfo);
     else
-        rc = RTLdrGetBits(pImage->pCacheEntry->hLdrMod, pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis);
+        rc = supHardNtLdrCacheEntryGetBits(pImage->pCacheEntry, &pbBits, pImage->uImageBase, supHardNtVpGetImport, pThis,
+                                           pThis->pErrInfo);
     if (RT_FAILURE(rc))
-        return supHardNtVpSetInfo2(pThis, rc, "%s: RTLdrGetBits failed: %Rrc", pImage->pszName, rc);
+        return rc;
 
     /* XP SP3 does not set ImageBase to load address. It fixes up the image on load time though. */
     if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
@@ -843,26 +844,22 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
             if (RT_FAILURE(rc))
                 return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'NtCreateSection': %Rrc", pImage->pszName, rc);
             aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
-            aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64);
+            aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
 
             /* Ignore our LdrLoadDll hack. */
             rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrLoadDll", &uValue);
             if (RT_FAILURE(rc))
                 return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrLoadDll': %Rrc", pImage->pszName, rc);
             aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
-            aSkipAreas[cSkipAreas++].cb = 5 + (ARCH_BITS == 64);
+            aSkipAreas[cSkipAreas++].cb = ARCH_BITS == 32 ? 5 : 12;
         }
 
-        if (   pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION
-            || pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY)
-        {
-            /* Ignore our patched LdrInitializeThunk hack. */
-            rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
-            if (RT_FAILURE(rc))
-                return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
-            aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
-            aSkipAreas[cSkipAreas++].cb = 10;
-        }
+        /* Ignore our patched LdrInitializeThunk hack. */
+        rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrInitializeThunk", &uValue);
+        if (RT_FAILURE(rc))
+            return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
+        aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
+        aSkipAreas[cSkipAreas++].cb = 14;
 
         /* LdrSystemDllInitBlock is filled in by the kernel. It mainly contains addresses of 32-bit ntdll method for wow64. */
         rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "LdrSystemDllInitBlock", &uValue);
@@ -927,7 +924,9 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
                     break;
                 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE:
                     fProt = PAGE_READWRITE;
-                    if (!suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll */
+                    if (   pThis->enmKind != SUPHARDNTVPKIND_VERIFY_ONLY
+                        && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION
+                        && !suplibHardenedMemComp(pThis->aSecHdrs[i].Name, ".mrdata", 8)) /* w8.1, ntdll. Changed by proc init. */
                         fProt = PAGE_READONLY;
                     break;
                 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE:
@@ -953,11 +952,14 @@ static int supHardNtVpVerifyImageMemoryCompare(PSUPHNTVPSTATE pThis, PSUPHNTVPIM
                                                pImage->pszName, i, pThis->aSecHdrs[i].Characteristics, uSectRva, cbMap);
             }
 
-            /* The section bits, only child purification verifies all bits . */
-            if (   pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION
-                || (   (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
+            /* The section bits. Child purification verifies all, normal
+               verification verifies all except where the executable is
+               concerned (due to opening vboxdrv during early process init). */
+            if (   (   (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
                     && !(pThis->aSecHdrs[i].Characteristics & IMAGE_SCN_MEM_WRITE))
-                || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ)
+                || (pThis->aSecHdrs[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == IMAGE_SCN_MEM_READ
+                || (pThis->enmKind == SUPHARDNTVPKIND_VERIFY_ONLY && pImage->fDll)
+                || pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
             {
                 rc = VINF_SUCCESS;
                 if (uRva < uSectRva && !pImage->fApiSetSchemaOnlySection1) /* Any gap worth checking? */
@@ -1033,7 +1035,7 @@ static int supHardNtVpVerifyImage(PSUPHNTVPSTATE pThis, PSUPHNTVPIMAGE pImage, H
  * @param   hThread             The thread.
  * @param   pErrInfo            Pointer to error info structure. Optional.
  */
-static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
 {
     /*
      * Use the ThreadAmILastThread request to check that there is only one
@@ -1056,7 +1058,6 @@ static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInf
 }
 
 
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
 /**
  * Verifies that there isn't a debugger attached to the process.
  *
@@ -1064,8 +1065,9 @@ static int supHardNtVpThread(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInf
  * @param   hProcess            The process.
  * @param   pErrInfo            Pointer to error info structure. Optional.
  */
-static int supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
 {
+#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
     /*
      * Use the ProcessDebugPort request to check there is no debugger
      * currently attached to the process.
@@ -1081,9 +1083,9 @@ static int supHardNtVpDebugger(HANDLE hProcess, PRTERRINFO pErrInfo)
     if (uPtr != 0)
         return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_DEBUGGED,
                                    "Debugger attached (%#zx)", uPtr);
+#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
     return VINF_SUCCESS;
 }
-#endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
 
 
 /**
@@ -1490,15 +1492,73 @@ static int supHardNtVpScanVirtualMemory(PSUPHNTVPSTATE pThis, HANDLE hProcess)
                  */
                 if (MemInfo.Type == MEM_PRIVATE)
                 {
-                    SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
-                                 uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
                     PVOID   pvFree = MemInfo.BaseAddress;
                     SIZE_T  cbFree = MemInfo.RegionSize;
-                    rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
-                    if (!NT_SUCCESS(rcNt))
-                        supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
-                                            "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
-                                            MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                    if (!(pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW))
+                    {
+                        SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Freeing exec mem at %p (%p LB %#zx)\n",
+                                     uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
+
+                        rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
+                        if (!NT_SUCCESS(rcNt))
+                            supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+                                                "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
+                                                MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                    }
+                    else
+                    {
+                        /* The Trend Micro sakfile.sys and Digital Guardian dgmaster.sys BSOD kludge. */
+                        SUP_DPRINTF(("supHardNtVpScanVirtualMemory: Replacing exec mem at %p (%p LB %#zx)\n",
+                                     uPtrWhere, MemInfo.BaseAddress, MemInfo.RegionSize));
+                        void *pvCopy = RTMemAllocZ(cbFree);
+                        if (pvCopy)
+                        {
+                            rcNt = supHardNtVpReadMem(pThis->hProcess, (uintptr_t)pvFree, pvCopy, cbFree);
+                            if (!NT_SUCCESS(rcNt))
+                                supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+                                                    "Error reading data from original alloc: %#x (%p LB %#zx)",
+                                                    rcNt, MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+
+                            rcNt = NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);
+                            if (NT_SUCCESS(rcNt))
+                            {
+                                pvFree = MemInfo.BaseAddress; cbFree = MemInfo.RegionSize;              /* fudge */
+                                NtFreeVirtualMemory(pThis->hProcess, &pvFree, &cbFree, MEM_RELEASE);    /* fudge */
+
+                                pvFree = MemInfo.BaseAddress;
+                                cbFree = MemInfo.RegionSize;
+                                rcNt = NtAllocateVirtualMemory(pThis->hProcess, &pvFree, 0, &cbFree, MEM_COMMIT, PAGE_READWRITE);
+                                if (!NT_SUCCESS(rcNt))
+                                    supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+                                                        "NtAllocateVirtualMemory (%p LB %#zx) failed with rcNt=%#x allocating "
+                                                        "replacement memory for working around buggy protection software. "
+                                                        "See VBoxStartup.log for more details",
+                                                        MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                                else if (pvFree != MemInfo.BaseAddress)
+                                    supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
+                                                        "We wanted NtAllocateVirtualMemory to get us %p LB %#zx, but it returned %p LB %#zx.",
+                                                        MemInfo.BaseAddress, MemInfo.RegionSize, pvFree, cbFree, rcNt);
+                                else
+                                {
+                                    SIZE_T cbWritten;
+                                    rcNt = NtWriteVirtualMemory(pThis->hProcess, MemInfo.BaseAddress, pvCopy, MemInfo.RegionSize,
+                                                                &cbWritten);
+                                    if (!NT_SUCCESS(rcNt))
+                                        supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+                                                            "NtWriteVirtualMemory (%p LB %#zx) failed: %#x",
+                                                            MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                                }
+                            }
+                            else
+                                supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+                                                    "NtFreeVirtualMemory (%p LB %#zx) failed: %#x",
+                                                    MemInfo.BaseAddress, MemInfo.RegionSize, rcNt);
+                            RTMemFree(pvCopy);
+                        }
+                        else
+                            supHardNtVpSetInfo2(pThis, VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED,
+                                                "RTMemAllocZ(%#zx) failed", MemInfo.RegionSize);
+                    }
                 }
                 /*
                  * Unmap mapped memory, failing that, drop exec privileges.
@@ -1585,7 +1645,7 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUT
 
 
 /**
- * Allocates a image bits buffer for use with RTLdrGetBits.
+ * Allocates a image bits buffer and calls RTLdrGetBits on them.
  *
  * An assumption here is that there won't ever be concurrent use of the cache.
  * It's currently 104% single threaded, non-reentrant.  Thus, we can't reuse the
@@ -1594,10 +1654,20 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryVerify(PSUPHNTLDRCACHEENTRY pEntry, PCRTUT
  * @returns VBox status code
  * @param   pEntry              The loader cache entry.
  * @param   ppbBits             Where to return the pointer to the allocation.
- * @param   pErRInfo            Where to return extened error information.
+ * @param   uBaseAddress        The image base address, see RTLdrGetBits.
+ * @param   pfnGetImport        Import getter, see RTLdrGetBits.
+ * @param   pvUser              The user argument for @a pfnGetImport.
+ * @param   pErrInfo            Where to return extened error information.
  */
-DECLHIDDEN(int) supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits, PRTERRINFO pErrInfo)
+DECLHIDDEN(int) supHardNtLdrCacheEntryGetBits(PSUPHNTLDRCACHEENTRY pEntry, uint8_t **ppbBits,
+                                              RTLDRADDR uBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
+                                              PRTERRINFO pErrInfo)
 {
+    int rc;
+
+    /*
+     * First time around we have to allocate memory before we can get the image bits.
+     */
     if (!pEntry->pbBits)
     {
         size_t cbBits = RTLdrSize(pEntry->hLdrMod);
@@ -1605,13 +1675,41 @@ DECLHIDDEN(int) supHardNtLdrCacheEntryAllocBits(PSUPHNTLDRCACHEENTRY pEntry, uin
             return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_IMAGE_TOO_BIG, "Image %s is too large: %zu bytes (%#zx).",
                                        pEntry->pszName, cbBits, cbBits);
 
-        pEntry->pbBits = (uint8_t *)suplibHardenedAllocZ(cbBits);
+        pEntry->pbBits = (uint8_t *)RTMemAllocZ(cbBits);
         if (!pEntry->pbBits)
             return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "Failed to allocate %zu bytes for image %s.",
                                        cbBits, pEntry->pszName);
+
+        pEntry->fValidBits = false; /* paranoia */
+
+        rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
+        if (RT_FAILURE(rc))
+            return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
+                                       pEntry->pszName, rc);
+        pEntry->uImageBase = uBaseAddress;
+        pEntry->fValidBits = pfnGetImport == NULL;
+
     }
+    /*
+     * Cache hit? No?
+     *
+     * Note! We cannot currently cache image bits for images with imports as we
+     *       don't control the way they're resolved.  Fortunately, NTDLL and
+     *       the VM process images all have no imports.
+     */
+    else if (   !pEntry->fValidBits
+             || pEntry->uImageBase != uBaseAddress
+             || pfnGetImport)
+    {
+        pEntry->fValidBits = false;
 
-    /** @todo Try cache RTLdrGetBits calls too. */
+        rc = RTLdrGetBits(pEntry->hLdrMod, pEntry->pbBits, uBaseAddress, pfnGetImport, pvUser);
+        if (RT_FAILURE(rc))
+            return supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY, "RTLdrGetBits failed on image %s: %Rrc",
+                                       pEntry->pszName, rc);
+        pEntry->uImageBase = uBaseAddress;
+        pEntry->fValidBits = pfnGetImport == NULL;
+    }
 
     *ppbBits = pEntry->pbBits;
     return VINF_SUCCESS;
@@ -1628,7 +1726,7 @@ static void supHardNTLdrCacheDeleteEntry(PSUPHNTLDRCACHEENTRY pEntry)
 {
     if (pEntry->pbBits)
     {
-        suplibHardenedFree(pEntry->pbBits);
+        RTMemFree(pEntry->pbBits);
         pEntry->pbBits = NULL;
     }
 
@@ -1650,8 +1748,10 @@ static void supHardNTLdrCacheDeleteEntry(PSUPHNTLDRCACHEENTRY pEntry)
         pEntry->hFile = NULL;
     }
 
-    pEntry->pszName   = NULL;
-    pEntry->fVerified = false;
+    pEntry->pszName    = NULL;
+    pEntry->fVerified  = false;
+    pEntry->fValidBits = false;
+    pEntry->uImageBase = 0;
 }
 
 #ifdef IN_RING3
@@ -1710,14 +1810,14 @@ static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *ps
 #endif
 
     NTSTATUS rcNt = NtCreateFile(&hFile,
-                                 GENERIC_READ,
+                                 GENERIC_READ | SYNCHRONIZE,
                                  &ObjAttr,
                                  &Ios,
                                  NULL /* Allocation Size*/,
                                  FILE_ATTRIBUTE_NORMAL,
                                  FILE_SHARE_READ,
                                  FILE_OPEN,
-                                 FILE_NON_DIRECTORY_FILE, /** @todo nonalert? */
+                                 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
                                  NULL /*EaBuffer*/,
                                  0 /*EaLength*/);
     if (NT_SUCCESS(rcNt))
@@ -1759,12 +1859,23 @@ static int supHardNtLdrCacheNewEntry(PSUPHNTLDRCACHEENTRY pEntry, const char *ps
     /*
      * Fill in the cache entry.
      */
-    pEntry->pszName   = pszName;
-    pEntry->hLdrMod   = hLdrMod;
-    pEntry->pNtViRdr  = pNtViRdr;
-    pEntry->hFile     = hFile;
-    pEntry->pbBits    = NULL;
-    pEntry->fVerified = false;
+    pEntry->pszName    = pszName;
+    pEntry->hLdrMod    = hLdrMod;
+    pEntry->pNtViRdr   = pNtViRdr;
+    pEntry->hFile      = hFile;
+    pEntry->pbBits     = NULL;
+    pEntry->fVerified  = false;
+    pEntry->fValidBits = false;
+    pEntry->uImageBase = ~(uintptr_t)0;
+
+#ifdef IN_SUP_HARDENED_R3
+    /*
+     * Log the image timestamp when in the hardened exe.
+     */
+    uint64_t uTimestamp = 0;
+    rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uTimestamp, sizeof(uint64_t));
+    SUP_DPRINTF(("%s: timestamp %#llx (rc=%Rrc)\n", pszName, uTimestamp, rc));
+#endif
 
     return VINF_SUCCESS;
 }
@@ -1786,9 +1897,9 @@ DECLHIDDEN(int) supHardNtLdrCacheOpen(const char *pszName, PSUPHNTLDRCACHEENTRY
      * Locate the dll.
      */
     uint32_t i = 0;
-    while (i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls))
-        if (!strcmp(pszName, g_apszSupNtVpAllowedDlls[i]))
-            break;
+    while (   i < RT_ELEMENTS(g_apszSupNtVpAllowedDlls)
+           && strcmp(pszName, g_apszSupNtVpAllowedDlls[i]))
+        i++;
     if (i >= RT_ELEMENTS(g_apszSupNtVpAllowedDlls))
         return VERR_FILE_NOT_FOUND;
     pszName = g_apszSupNtVpAllowedDlls[i];
@@ -1916,7 +2027,7 @@ static int supHardNtVpCheckExe(PSUPHNTVPSTATE pThis, HANDLE hProcess)
      */
     int             rc;
     ULONG           cbUniStr = sizeof(UNICODE_STRING) + RTPATH_MAX * sizeof(RTUTF16);
-    PUNICODE_STRING pUniStr  = (PUNICODE_STRING)suplibHardenedAllocZ(cbUniStr);
+    PUNICODE_STRING pUniStr  = (PUNICODE_STRING)RTMemAllocZ(cbUniStr);
     if (!pUniStr)
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_MEMORY,
                                   "Error allocating %zu bytes for process name.", cbUniStr);
@@ -1937,7 +2048,7 @@ static int supHardNtVpCheckExe(PSUPHNTVPSTATE pThis, HANDLE hProcess)
     else
         rc = supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR,
                                  "NtQueryInformationProcess/ProcessImageFileName failed: %#x", rcNt);
-    suplibHardenedFree(pUniStr);
+    RTMemFree(pUniStr);
     if (RT_FAILURE(rc))
         return rc;
 
@@ -2032,7 +2143,7 @@ static int supHardNtVpCheckDlls(PSUPHNTVPSTATE pThis, HANDLE hProcess)
     if (iNtDll == UINT32_MAX)
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_NTDLL_MAPPING,
                                    "The process has no NTDLL.DLL.");
-    if (iKernel32 == UINT32_MAX && pThis->enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
+    if (iKernel32 == UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_SELF_PURIFICATION)
         return supHardNtVpSetInfo2(pThis, VERR_SUP_VP_NO_KERNEL32_MAPPING,
                                    "The process has no KERNEL32.DLL.");
     else if (iKernel32 != UINT32_MAX && pThis->enmKind == SUPHARDNTVPKIND_CHILD_PURIFICATION)
@@ -2072,11 +2183,12 @@ static int supHardNtVpCheckDlls(PSUPHNTVPSTATE pThis, HANDLE hProcess)
  * @param   hProcess            The process to verify.
  * @param   hThread             A thread in the process (the caller).
  * @param   enmKind             The kind of process verification to perform.
+ * @param   fFlags              Valid combination of SUPHARDNTVP_F_XXX flags.
  * @param   pErrInfo            Pointer to error info structure. Optional.
  * @param   pcFixes             Where to return the number of fixes made during
  *                              purification.  Optional.
  */
-DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind,
+DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUPHARDNTVPKIND enmKind, uint32_t fFlags,
                                             uint32_t *pcFixes, PRTERRINFO pErrInfo)
 {
     if (pcFixes)
@@ -2089,19 +2201,18 @@ DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUP
     int rc = VINF_SUCCESS;
     if (enmKind != SUPHARDNTVPKIND_CHILD_PURIFICATION)
        rc = supHardNtVpThread(hProcess, hThread, pErrInfo);
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
     if (RT_SUCCESS(rc))
         rc = supHardNtVpDebugger(hProcess, pErrInfo);
-#endif
     if (RT_SUCCESS(rc))
     {
         /*
          * Allocate and initialize memory for the state.
          */
-        PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)suplibHardenedAllocZ(sizeof(*pThis));
+        PSUPHNTVPSTATE pThis = (PSUPHNTVPSTATE)RTMemAllocZ(sizeof(*pThis));
         if (pThis)
         {
             pThis->enmKind  = enmKind;
+            pThis->fFlags   = fFlags;
             pThis->rcResult = VINF_SUCCESS;
             pThis->hProcess = hProcess;
             pThis->pErrInfo = pErrInfo;
@@ -2127,7 +2238,7 @@ DECLHIDDEN(int) supHardenedWinVerifyProcess(HANDLE hProcess, HANDLE hThread, SUP
             for (uint32_t i = 0; i < pThis->cImages; i++)
                 supHardNTLdrCacheDeleteEntry(&pThis->aImages[i].CacheEntry);
 #endif
-            suplibHardenedFree(pThis);
+            RTMemFree(pThis);
         }
         else
             rc = supHardNtVpSetInfo1(pErrInfo, VERR_SUP_VP_NO_MEMORY_STATE,
diff --git a/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
index 655c68a..99ef643 100644
--- a/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
@@ -109,14 +109,14 @@ int suplibOsHardenedVerifyTerm(void)
 }
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
      * Make sure the image verifier is fully initialized.
      */
     int rc = suplibOsHardenedVerifyInit();
     if (RT_FAILURE(rc))
-        return rc;
+        return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc);
 
     /*
      * Done if of pre-inited.
@@ -157,70 +157,109 @@ int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
         hDevice = RTNT_INVALID_HANDLE_VALUE;
 
         NTSTATUS rcNt = NtCreateFile(&hDevice,
-                                     GENERIC_READ | GENERIC_WRITE,
+                                     GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
                                      &ObjAttr,
                                      &Ios,
                                      NULL /* Allocation Size*/,
                                      FILE_ATTRIBUTE_NORMAL,
                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
                                      FILE_OPEN,
-                                     FILE_NON_DIRECTORY_FILE,
+                                     FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */
                                      NULL /*EaBuffer*/,
                                      0 /*EaLength*/);
         if (NT_SUCCESS(rcNt))
             rcNt = Ios.Status;
-        if (!NT_SUCCESS(rcNt))
+        if (NT_SUCCESS(rcNt))
         {
-#ifndef IN_SUP_HARDENED_R3
             /*
-             * Failed to open, try starting the service and reopen the device
-             * exactly once.
+             * We're good.
              */
-            if (cTry == 0 && !NT_SUCCESS(rcNt))
-            {
-                cTry++;
-                suplibOsStartService();
-                continue;
-            }
+            pThis->hDevice       = hDevice;
+            pThis->fUnrestricted = fUnrestricted;
+            return VINF_SUCCESS;
+        }
+
+#ifndef IN_SUP_HARDENED_R3
+        /*
+         * Failed to open, try starting the service and reopen the device
+         * exactly once.
+         */
+        if (cTry == 0 && !NT_SUCCESS(rcNt))
+        {
+            cTry++;
+            suplibOsStartService();
+            continue;
+        }
 #endif
-            switch (rcNt)
+
+        /*
+         * Translate the error code.
+         */
+        switch (rcNt)
+        {
+            /** @todo someone must test what is actually returned. */
+            case STATUS_DEVICE_DOES_NOT_EXIST:
+            case STATUS_DEVICE_NOT_CONNECTED:
+            //case ERROR_BAD_DEVICE:
+            case STATUS_DEVICE_REMOVED:
+            //case ERROR_DEVICE_NOT_AVAILABLE:
+                rc = VERR_VM_DRIVER_LOAD_ERROR;
+                break;
+            case STATUS_OBJECT_PATH_NOT_FOUND:
+            case STATUS_NO_SUCH_DEVICE:
+            case STATUS_NO_SUCH_FILE:
+            case STATUS_OBJECT_NAME_NOT_FOUND:
+                rc = VERR_VM_DRIVER_NOT_INSTALLED;
+                break;
+            case STATUS_ACCESS_DENIED:
+            case STATUS_SHARING_VIOLATION:
+                rc = VERR_VM_DRIVER_NOT_ACCESSIBLE;
+                break;
+            case STATUS_UNSUCCESSFUL:
+                rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
+                break;
+            case STATUS_TRUST_FAILURE:
+                rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
+                break;
+            case STATUS_TOO_LATE:
+                rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+                break;
+            default:
+                if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
+                    rc = SUP_NT_STATUS_TO_VBOX(rcNt);
+                else
+                    rc = VERR_VM_DRIVER_OPEN_ERROR;
+                break;
+        }
+
+#ifdef IN_SUP_HARDENED_R3
+        /*
+         * Get more details from VBoxDrvErrorInfo if present.
+         */
+        if (pErrInfo && pErrInfo->cbMsg > 32)
+        {
+            /* Prefix. */
+            size_t      cchPrefix;
+            const char *pszDefine = RTErrGetDefine(rc);
+            if (strncmp(pszDefine, RT_STR_TUPLE("Unknown")))
+                cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%s): ", rcNt, pszDefine);
+            else
+                cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc);
+
+            /* Get error info. */
+            supR3HardenedWinReadErrorInfoDevice(pErrInfo->pszMsg + cchPrefix, pErrInfo->cbMsg - cchPrefix, "");
+            if (pErrInfo->pszMsg[cchPrefix] != '\0')
             {
-                /** @todo someone must test what is actually returned. */
-                case STATUS_DEVICE_DOES_NOT_EXIST:
-                case STATUS_DEVICE_NOT_CONNECTED:
-                //case ERROR_BAD_DEVICE:
-                case STATUS_DEVICE_REMOVED:
-                //case ERROR_DEVICE_NOT_AVAILABLE:
-                    return VERR_VM_DRIVER_LOAD_ERROR;
-                case STATUS_OBJECT_PATH_NOT_FOUND:
-                case STATUS_NO_SUCH_DEVICE:
-                case STATUS_NO_SUCH_FILE:
-                case STATUS_OBJECT_NAME_NOT_FOUND:
-                    return VERR_VM_DRIVER_NOT_INSTALLED;
-                case STATUS_ACCESS_DENIED:
-                case STATUS_SHARING_VIOLATION:
-                    return VERR_VM_DRIVER_NOT_ACCESSIBLE;
-                case STATUS_UNSUCCESSFUL:
-                    return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
-                case STATUS_TRUST_FAILURE:
-                    return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
-                case STATUS_TOO_LATE:
-                    return VERR_SUPDRV_HARDENING_EVIL_HANDLE;
-                default:
-                    if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
-                        return SUP_NT_STATUS_TO_VBOX(rcNt);
-                    return VERR_VM_DRIVER_OPEN_ERROR;
+                pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
+                pErrInfo->rc      = rc;
+                *penmWhat = kSupInitOp_Integrity;
             }
+            else
+                pErrInfo->pszMsg[0] = '\0';
         }
-        break;
+#endif
+        return rc;
     }
-
-    /*
-     * We're done.
-     */
-    pThis->hDevice       = hDevice;
-    pThis->fUnrestricted = fUnrestricted;
-    return VINF_SUCCESS;
 }
 
 
@@ -364,6 +403,8 @@ static int suplibOsStopService(void)
         }
         CloseServiceHandle(hSMgr);
     }
+    else
+        rc = RTErrConvertFromWin32(dwErr);
     return rc;
 }
 
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
index 29c8eae..5f7b467 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
@@ -91,7 +91,7 @@
     do { \
         BOOL fRcAssert = (a_Expr); \
         if (fRcAssert == FALSE) \
-            supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, GetLastError()); \
+            supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, RtlGetLastWin32Error()); \
     } while (0)
 
 
@@ -173,9 +173,95 @@ typedef struct VERIFIERCACHEIMPORT
 typedef VERIFIERCACHEIMPORT *PVERIFIERCACHEIMPORT;
 
 
+/**
+ * Child requests.
+ */
+typedef enum SUPR3WINCHILDREQ
+{
+    /** Perform child purification and close full access handles (must be zero). */
+    kSupR3WinChildReq_PurifyChildAndCloseHandles = 0,
+    /** Close the events, we're good on our own from here on.  */
+    kSupR3WinChildReq_CloseEvents,
+    /** Reporting error. */
+    kSupR3WinChildReq_Error,
+    /** End of valid requests. */
+    kSupR3WinChildReq_End
+} SUPR3WINCHILDREQ;
+
+/**
+ * Child process parameters.
+ */
+typedef struct SUPR3WINPROCPARAMS
+{
+    /** The event semaphore the child will be waiting on. */
+    HANDLE                      hEvtChild;
+    /** The event semaphore the parent will be waiting on. */
+    HANDLE                      hEvtParent;
+
+    /** The address of the NTDLL. This is only valid during the very early
+     * initialization as we abuse for thread creation protection. */
+    uintptr_t                   uNtDllAddr;
+
+    /** The requested operation (set by the child). */
+    SUPR3WINCHILDREQ            enmRequest;
+    /** The last status. */
+    int32_t                     rc;
+    /** The init operation the error relates to if message, kSupInitOp_Invalid if
+     *  not message. */
+    SUPINITOP                   enmWhat;
+    /** Where if message. */
+    char                        szWhere[80];
+    /** Error message / path name string space. */
+    char                        szErrorMsg[4096];
+} SUPR3WINPROCPARAMS;
+
+
+/**
+ * Child process data structure for use during child process init setup and
+ * purification.
+ */
+typedef struct SUPR3HARDNTCHILD
+{
+    /** Process handle. */
+    HANDLE                      hProcess;
+    /** Primary thread handle. */
+    HANDLE                      hThread;
+    /** Handle to the parent process, if we're the middle (stub) process. */
+    HANDLE                      hParent;
+    /** The event semaphore the child will be waiting on. */
+    HANDLE                      hEvtChild;
+    /** The event semaphore the parent will be waiting on. */
+    HANDLE                      hEvtParent;
+    /** The address of NTDLL in the child. */
+    uintptr_t                   uNtDllAddr;
+    /** The address of NTDLL in this process. */
+    uintptr_t                   uNtDllParentAddr;
+    /** Which respawn number this is (1 = stub, 2 = VM). */
+    int                         iWhich;
+    /** The basic process info. */
+    PROCESS_BASIC_INFORMATION   BasicInfo;
+    /** The probable size of the PEB. */
+    size_t                      cbPeb;
+    /** The pristine process environment block. */
+    PEB                         Peb;
+    /** The child process parameters. */
+    SUPR3WINPROCPARAMS          ProcParams;
+} SUPR3HARDNTCHILD;
+/** Pointer to a child process data structure. */
+typedef SUPR3HARDNTCHILD *PSUPR3HARDNTCHILD;
+
+
 /*******************************************************************************
 *   Global Variables                                                           *
 *******************************************************************************/
+/** Process parameters.  Specified by parent if VM process, see
+ *  supR3HardenedVmProcessInit. */
+static SUPR3WINPROCPARAMS   g_ProcParams = { NULL, NULL, 0, (SUPR3WINCHILDREQ)0, 0 };
+/** Set if supR3HardenedEarlyProcessInit was invoked. */
+bool                        g_fSupEarlyProcessInit = false;
+/** Set if the stub device has been opened (stub process only). */
+bool                        g_fSupStubOpened = false;
+
 /** @name Global variables initialized by suplibHardenedWindowsMain.
  * @{ */
 /** Combined windows NT version number.  See SUP_MAKE_NT_VER_COMBINED. */
@@ -194,27 +280,40 @@ uint32_t                    g_offSupLibHardenedExeNtName;
 
 /** @name Hook related variables.
  * @{ */
-/** The jump back address of the patched NtCreateSection. */
-extern "C" PFNRT            g_pfnNtCreateSectionJmpBack = NULL;
 /** Pointer to the bit of assembly code that will perform the original
  *  NtCreateSection operation. */
 static NTSTATUS (NTAPI *    g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
                                                       PLARGE_INTEGER, ULONG, ULONG, HANDLE);
-#if 0
-/** The jump back address of the patched LdrLoadDll. */
-extern "C" PFNRT            g_pfnLdrLoadDllJmpBack = NULL;
-#endif
+/** Pointer to the NtCreateSection function in NtDll (for patching purposes). */
+static uint8_t             *g_pbNtCreateSection;
+/** The patched NtCreateSection bytes (for restoring). */
+static uint8_t              g_abNtCreateSectionPatch[16];
 /** Pointer to the bit of assembly code that will perform the original
  *  LdrLoadDll operation. */
 static NTSTATUS (NTAPI *    g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
+/** Pointer to the LdrLoadDll function in NtDll (for patching purposes). */
+static uint8_t             *g_pbLdrLoadDll;
+/** The patched LdrLoadDll bytes (for restoring). */
+static uint8_t              g_abLdrLoadDllPatch[16];
+
 /** The hash table of verifier cache . */
 static PVERIFIERCACHEENTRY  volatile g_apVerifierCache[128];
 /** Queue of cached images which needs WinVerifyTrust to check them. */
 static PVERIFIERCACHEENTRY  volatile g_pVerifierCacheTodoWvt = NULL;
 /** Queue of cached images which needs their imports checked. */
 static PVERIFIERCACHEIMPORT volatile g_pVerifierCacheTodoImports = NULL;
+
+/** The windows path to dir \\SystemRoot\\System32 directory (technically
+ *  this whatever \KnownDlls\KnownDllPath points to). */
+SUPSYSROOTDIRBUF            g_System32WinPath;
 /** @ */
 
+/** Positive if the DLL notification callback has been registered, counts
+ * registration attempts as negative. */
+static int                  g_cDllNotificationRegistered = 0;
+/** The registration cookie of the DLL notification callback. */
+static PVOID                g_pvDllNotificationCookie = NULL;
+
 /** Static error info structure used during init. */
 static RTERRINFOSTATIC      g_ErrInfoStatic;
 
@@ -228,6 +327,42 @@ static bool                 g_fSupInitThunkSelfPatched;
  * thread creation in this process. */
 static uint8_t              g_abLdrInitThunkSelfBackup[16];
 
+/** Mask of adversaries that we've detected (SUPHARDNT_ADVERSARY_XXX). */
+static uint32_t             g_fSupAdversaries = 0;
+/** @name SUPHARDNT_ADVERSARY_XXX - Adversaries
+ * @{ */
+/** Symantec endpoint protection or similar including SysPlant.sys. */
+#define SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT       RT_BIT_32(0)
+/** Symantec Norton 360. */
+#define SUPHARDNT_ADVERSARY_SYMANTEC_N360           RT_BIT_32(1)
+/** Avast! */
+#define SUPHARDNT_ADVERSARY_AVAST                   RT_BIT_32(2)
+/** TrendMicro OfficeScan and probably others. */
+#define SUPHARDNT_ADVERSARY_TRENDMICRO              RT_BIT_32(3)
+/** TrendMicro potentially buggy sakfile.sys. */
+#define SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE      RT_BIT_32(4)
+/** McAfee.  */
+#define SUPHARDNT_ADVERSARY_MCAFEE                  RT_BIT_32(5)
+/** Kaspersky or OEMs of it.  */
+#define SUPHARDNT_ADVERSARY_KASPERSKY               RT_BIT_32(6)
+/** Malwarebytes Anti-Malware (MBAM). */
+#define SUPHARDNT_ADVERSARY_MBAM                    RT_BIT_32(7)
+/** AVG Internet Security. */
+#define SUPHARDNT_ADVERSARY_AVG                     RT_BIT_32(8)
+/** Panda Security. */
+#define SUPHARDNT_ADVERSARY_PANDA                   RT_BIT_32(9)
+/** Microsoft Security Essentials. */
+#define SUPHARDNT_ADVERSARY_MSE                     RT_BIT_32(10)
+/** Comodo. */
+#define SUPHARDNT_ADVERSARY_COMODO                  RT_BIT_32(11)
+/** Check Point's Zone Alarm (may include Kaspersky).  */
+#define SUPHARDNT_ADVERSARY_ZONE_ALARM              RT_BIT_32(12)
+/** Digital guardian.  */
+#define SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN        RT_BIT_32(13)
+/** Unknown adversary detected while waiting on child. */
+#define SUPHARDNT_ADVERSARY_UNKNOWN                 RT_BIT_32(31)
+/** @} */
+
 
 /*******************************************************************************
 *   Internal Functions                                                         *
@@ -235,17 +370,9 @@ static uint8_t              g_abLdrInitThunkSelfBackup[16];
 static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAccess, PULONG pfProtect,
                                          bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
                                          bool *pfQuietFailure);
-
-#ifdef RT_ARCH_AMD64
-# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
-# include "NtCreateSection-template-amd64-syscall-type-1.h"
-# undef SYSCALL
-#endif
-#ifdef RT_ARCH_X86
-# define SYSCALL(a_Num) DECLASM(void) RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num)(void)
-# include "NtCreateSection-template-x86-syscall-type-1.h"
-# undef SYSCALL
-#endif
+static void     supR3HardenedWinRegisterDllNotificationCallback(void);
+static void     supR3HardenedWinReInstallHooks(bool fFirst);
+DECLASM(void)   supR3HardenedEarlyProcessInitThunk(void);
 
 
 
@@ -288,52 +415,25 @@ static size_t suplibHardenedWStrLen(PCRTUTF16 pwsz)
 
 
 /**
- * Allocate zero filled memory on the heap.
- *
- * @returns Pointer to the memory.  Will never return NULL, triggers a fatal
- *          error instead.
- * @param   cb                  The number of bytes to allocate.
+ * Our version of GetTickCount.
+ * @returns Millisecond timestamp.
  */
-DECLHIDDEN(void *) suplibHardenedAllocZ(size_t cb)
+static uint64_t supR3HardenedWinGetMilliTS(void)
 {
-    void *pv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
-    if (!pv)
-        supR3HardenedFatal("HeapAlloc failed to allocate %zu bytes.\n", cb);
-    return pv;
-}
+    PKUSER_SHARED_DATA pUserSharedData = (PKUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
 
+    /* use interrupt time */
+    LARGE_INTEGER Time;
+    do
+    {
+        Time.HighPart = pUserSharedData->InterruptTime.High1Time;
+        Time.LowPart  = pUserSharedData->InterruptTime.LowPart;
+    } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart);
 
-/**
- * Reallocates memory on the heap.
- *
- * @returns Pointer to the resized memory block.  Will never return NULL,
- *          triggers a fatal error instead.
- * @param   pvOld               The old memory block.
- * @param   cbNew               The new block size.
- */
-DECLHIDDEN(void *) suplibHardenedReAlloc(void *pvOld, size_t cbNew)
-{
-    if (!pvOld)
-        return suplibHardenedAllocZ(cbNew);
-    void *pv = HeapReAlloc(GetProcessHeap(), 0 /*dwFlags*/, pvOld, cbNew);
-    if (!pv)
-        supR3HardenedFatal("HeapReAlloc failed to allocate %zu bytes.\n", cbNew);
-    return pv;
+    return (uint64_t)Time.QuadPart / 10000;
 }
 
 
-/**
- * Frees memory allocated by suplibHardenedAlloc, suplibHardenedAllocZ or
- * suplibHardenedReAlloc.
- *
- * @param   pv                  Pointer to the memeory to be freed.
- */
-DECLHIDDEN(void) suplibHardenedFree(void *pv)
-{
-    if (pv)
-        HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pv);
-}
-
 
 /**
  * Wrapper around LoadLibraryEx that deals with the UTF-8 to UTF-16 conversion
@@ -373,7 +473,7 @@ DECLHIDDEN(void *) supR3HardenedWinLoadLibrary(const char *pszName, bool fSystem
         if (   !pvRet
             && fFlags
             && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
-            && GetLastError() == ERROR_INVALID_PARAMETER)
+            && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
             pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, 0);
 
         return pvRet;
@@ -482,8 +582,8 @@ static bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 paw
         RTUTF16 wcRight = *pawcRight++;
         if (wcLeft != wcRight)
         {
-            wcLeft = wcLeft  != '/' ? RT_C_TO_LOWER(wcLeft)  : '\\';
-            wcLeft = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
+            wcLeft  = wcLeft  != '/' ? RT_C_TO_LOWER(wcLeft)  : '\\';
+            wcRight = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
             if (wcLeft != wcRight)
                 return false;
         }
@@ -510,8 +610,7 @@ static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE h
     /*
      * Allocate and initalize a new entry.
      */
-    PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                                                sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
+    PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)RTMemAllocZ(sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
     if (pEntry)
     {
         pEntry->pNext           = NULL;
@@ -556,7 +655,7 @@ static void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE h
         }
 
         /* Duplicate entry (may happen due to races). */
-        HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pEntry);
+        RTMemFree(pEntry);
     }
     NtClose(hFile);
 }
@@ -728,7 +827,7 @@ DECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PC
                     uint32_t cbNameAligned = RT_ALIGN_32(cbName, sizeof(RTUTF16));
                     uint32_t cbNeeded      = RT_OFFSETOF(VERIFIERCACHEIMPORT, szName[cbNameAligned])
                                            + (pawcDir ? (cwcDir + 1) * sizeof(RTUTF16) : 0);
-                    PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeeded);
+                    PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)RTMemAllocZ(cbNeeded);
                     if (pImport)
                     {
                         /* Init it. */
@@ -800,6 +899,7 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
                 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Processing '%s'...\n", pCur->szName));
 
                 NTSTATUS    rcNt;
+                NTSTATUS    rcNtRedir = 0x22222222;
                 HANDLE      hFile = INVALID_HANDLE_VALUE;
                 RTUTF16     wszPath[260 + 260]; /* Assumes we've limited the import name length to 256. */
                 AssertCompile(sizeof(wszPath) > sizeof(g_System32NtPath));
@@ -826,18 +926,18 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
                     UNICODE_STRING  UniStrDynamic = { 0, 0, NULL };
                     PUNICODE_STRING pUniStrResult = NULL;
 
-                    rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
-                                                                    &UniStrName,
-                                                                    (PUNICODE_STRING)&s_DefaultSuffix,
-                                                                    &UniStrStatic,
-                                                                    &UniStrDynamic,
-                                                                    &pUniStrResult,
-                                                                    NULL /*pNewFlags*/,
-                                                                    NULL /*pcbFilename*/,
-                                                                    NULL /*pcbNeeded*/);
-                    if (NT_SUCCESS(rcNt))
+                    rcNtRedir = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
+                                                                         &UniStrName,
+                                                                         (PUNICODE_STRING)&s_DefaultSuffix,
+                                                                         &UniStrStatic,
+                                                                         &UniStrDynamic,
+                                                                         &pUniStrResult,
+                                                                         NULL /*pNewFlags*/,
+                                                                         NULL /*pcbFilename*/,
+                                                                         NULL /*pcbNeeded*/);
+                    if (NT_SUCCESS(rcNtRedir))
                     {
-                        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+                        IO_STATUS_BLOCK     Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
                         OBJECT_ATTRIBUTES   ObjAttr;
                         InitializeObjectAttributes(&ObjAttr, pUniStrResult,
                                                    OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
@@ -854,7 +954,14 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
                                             0 /*EaLength*/);
                         if (NT_SUCCESS(rcNt))
                             rcNt = Ios.Status;
-                        if (!NT_SUCCESS(rcNt))
+                        if (NT_SUCCESS(rcNt))
+                        {
+                            /* For accurate logging. */
+                            size_t cwcCopy = RT_MIN(pUniStrResult->Length / sizeof(RTUTF16), RT_ELEMENTS(wszPath) - 1);
+                            memcpy(wszPath, pUniStrResult->Buffer, cwcCopy * sizeof(RTUTF16));
+                            wszPath[cwcCopy] = '\0';
+                        }
+                        else
                             hFile = INVALID_HANDLE_VALUE;
                         RtlFreeUnicodeString(&UniStrDynamic);
                     }
@@ -937,7 +1044,8 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
                  */
                 if (hFile != INVALID_HANDLE_VALUE)
                 {
-                    SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls'\n", pCur->szName, wszPath));
+                    SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls' [rcNtRedir=%#x]\n",
+                                 pCur->szName, wszPath, rcNtRedir));
 
                     ULONG fAccess = 0;
                     ULONG fProtect = 0;
@@ -952,7 +1060,7 @@ static void supR3HardenedWinVerifyCacheProcessImportTodos(void)
             else
                 SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName));
 
-            HeapFree(GetProcessHeap(), 0 /* dwFlags*/, pCur);
+            RTMemFree(pCur);
         } while (pTodo);
     }
 }
@@ -1076,7 +1184,7 @@ static void supR3HardenedWinFix8dot3Path(HANDLE hFile, PUNICODE_STRING pUniStr)
 
         RTUTF16 wc;
         PRTUTF16 pwszFixEnd = pwszFix;
-        while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '//')
+        while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '/')
             pwszFixEnd++;
         if (wc == '\0')
             break;
@@ -1442,7 +1550,7 @@ static NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, PULONG pfAcc
                            "supR3HardenedScreenImage/%s: rc=%Rrc fImage=%d fProtect=%#x fAccess=%#x %ls: %s\n",
                            pszCaller, rc, fImage, *pfAccess, *pfProtect, uBuf.UniStr.Buffer, ErrInfo.pszMsg);
         if (hMyFile != hFile)
-            NtClose(hMyFile);
+            supR3HardenedWinVerifyCacheInsert(&uBuf.UniStr, hMyFile, rc, fWinVerifyTrust, fFlags);
         return STATUS_TRUST_FAILURE;
     }
 
@@ -1534,7 +1642,7 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
                                                    | PAGE_EXECUTE_READWRITE));
         if (fImage || fExecMap || fExecProt)
         {
-            DWORD dwSavedLastError = GetLastError();
+            DWORD dwSavedLastError = RtlGetLastWin32Error();
 
             bool fCallRealApi;
             //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 1\n"));
@@ -1542,7 +1650,7 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
                                                      "NtCreateSection", true /*fAvoidWinVerifyTrust*/, NULL /*pfQuietFailure*/);
             //SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
 
-            SetLastError(dwSavedLastError);
+            RtlRestoreLastWin32Error(dwSavedLastError);
 
             if (!NT_SUCCESS(rcNt))
                 return rcNt;
@@ -1561,6 +1669,40 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
 
 
 /**
+ * Helper for supR3HardenedMonitor_LdrLoadDll.
+ *
+ * @returns NT status code.
+ * @param   pwszPath        The path destination buffer.
+ * @param   cwcPath         The size of the path buffer.
+ * @param   pUniStrResult   The result string.
+ * @param   pOrgName        The orignal name (for errors).
+ * @param   pcwc            Where to return the actual length.
+ */
+static NTSTATUS supR3HardenedCopyRedirectionResult(WCHAR *pwszPath, size_t cwcPath, PUNICODE_STRING pUniStrResult,
+                                                   PUNICODE_STRING pOrgName, UINT *pcwc)
+{
+    UINT cwc;
+    *pcwc = cwc = pUniStrResult->Length / sizeof(WCHAR);
+    if (pUniStrResult->Buffer == pwszPath)
+        pwszPath[cwc] = '\0';
+    else
+    {
+        if (cwc > cwcPath - 1)
+        {
+            supR3HardenedError(VINF_SUCCESS, false,
+                               "supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
+                               pOrgName->Length / sizeof(WCHAR), pOrgName->Buffer,
+                               pUniStrResult->Length / sizeof(WCHAR), pUniStrResult->Buffer);
+            return STATUS_NAME_TOO_LONG;
+        }
+        memcpy(&pwszPath[0], pUniStrResult->Buffer, pUniStrResult->Length);
+        pwszPath[cwc] = '\0';
+    }
+    return STATUS_SUCCESS;
+}
+
+
+/**
  * Hooks that intercepts LdrLoadDll calls.
  *
  * Two purposes:
@@ -1580,10 +1722,20 @@ supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POB
 static NTSTATUS NTAPI
 supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod)
 {
-    DWORD    dwSavedLastError = GetLastError();
+    DWORD    dwSavedLastError = RtlGetLastWin32Error();
     NTSTATUS rcNt;
 
     /*
+     * Make sure the DLL notification callback is registered.  If we could, we
+     * would've done this during early process init, but due to lack of heap
+     * and uninitialized loader lock, it's not possible that early on.
+     *
+     * The callback protects our NtDll hooks from getting unhooked by
+     * "friendly" fire from the AV crowd.
+     */
+    supR3HardenedWinRegisterDllNotificationCallback();
+
+    /*
      * Process WinVerifyTrust todo before and after.
      */
     supR3HardenedWinVerifyCacheProcessWvtTodos();
@@ -1594,12 +1746,13 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
     if (!pName || pName->Length == 0)
     {
         supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n");
-        SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_INVALID_PARAMETER));
+        SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x (pName=%p)\n", STATUS_INVALID_PARAMETER, pName));
+        RtlRestoreLastWin32Error(dwSavedLastError);
         return STATUS_INVALID_PARAMETER;
     }
-    SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls\n",
+    /*SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls\n",
                  (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
-                 !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
+                 !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));*/
 
     /*
      * Reject long paths that's close to the 260 limit without looking.
@@ -1608,6 +1761,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
     {
         supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length);
         SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
+        RtlRestoreLastWin32Error(dwSavedLastError);
         return STATUS_NAME_TOO_LONG;
     }
 
@@ -1616,7 +1770,12 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
      */
     bool            fSkipValidation = false;
     WCHAR           wszPath[260];
+    static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
+    UNICODE_STRING  UniStrStatic   = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
+    UNICODE_STRING  UniStrDynamic  = { 0, 0, NULL };
+    PUNICODE_STRING pUniStrResult  = NULL;
     UNICODE_STRING  ResolvedName;
+
     if (   (   pName->Length >= 4 * sizeof(WCHAR)
             && RT_C_IS_ALPHA(pName->Buffer[0])
             && pName->Buffer[1] == ':'
@@ -1625,8 +1784,41 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
             && RTPATH_IS_SLASH(pName->Buffer[1]) )
        )
     {
-        memcpy(wszPath, pName->Buffer, pName->Length);
-        wszPath[pName->Length / sizeof(WCHAR)] = '\0';
+        rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
+                                                        pName,
+                                                        (PUNICODE_STRING)&s_DefaultSuffix,
+                                                        &UniStrStatic,
+                                                        &UniStrDynamic,
+                                                        &pUniStrResult,
+                                                        NULL /*pNewFlags*/,
+                                                        NULL /*pcbFilename*/,
+                                                        NULL /*pcbNeeded*/);
+        if (NT_SUCCESS(rcNt))
+        {
+            UINT cwc;
+            rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
+            RtlFreeUnicodeString(&UniStrDynamic);
+            if (!NT_SUCCESS(rcNt))
+            {
+                SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
+                RtlRestoreLastWin32Error(dwSavedLastError);
+                return rcNt;
+            }
+
+            ResolvedName.Buffer = wszPath;
+            ResolvedName.Length = (USHORT)(cwc * sizeof(WCHAR));
+            ResolvedName.MaximumLength = ResolvedName.Length + sizeof(WCHAR);
+
+            SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: '%.*ls' -> '%.*ls' [redir]\n",
+                         (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer,
+                         ResolvedName.Length / sizeof(WCHAR), ResolvedName.Buffer, rcNt));
+            pName = &ResolvedName;
+        }
+        else
+        {
+            memcpy(wszPath, pName->Buffer, pName->Length);
+            wszPath[pName->Length / sizeof(WCHAR)] = '\0';
+        }
     }
     /*
      * Not an absolute path.  Check if it's one of those special API set DLLs
@@ -1678,6 +1870,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
                                "supR3HardenedMonitor_LdrLoadDll: relative name not permitted: %.*ls\n",
                                cwcName, pawcName);
             SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_OBJECT_NAME_INVALID));
+            RtlRestoreLastWin32Error(dwSavedLastError);
             return STATUS_OBJECT_NAME_INVALID;
         }
 
@@ -1686,11 +1879,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
          * API here, which as always is a bit risky...  ASSUMES that the API
          * returns a full DOS path.
          */
-        UINT            cwc;
-        static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
-        UNICODE_STRING  UniStrStatic   = { 0, (USHORT)sizeof(wszPath) - sizeof(WCHAR), wszPath };
-        UNICODE_STRING  UniStrDynamic = { 0, 0, NULL };
-        PUNICODE_STRING pUniStrResult  = NULL;
+        UINT cwc;
         rcNt = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
                                                         pName,
                                                         (PUNICODE_STRING)&s_DefaultSuffix,
@@ -1702,25 +1891,14 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
                                                         NULL /*pcbNeeded*/);
         if (NT_SUCCESS(rcNt))
         {
-            cwc = pUniStrResult->Length / sizeof(WCHAR);
-            if (pUniStrResult != &UniStrDynamic)
-                wszPath[cwc] = '\0';
-            else
+            rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
+            RtlFreeUnicodeString(&UniStrDynamic);
+            if (!NT_SUCCESS(rcNt))
             {
-                if (pUniStrResult->Length > sizeof(wszPath) - sizeof(WCHAR))
-                {
-                    supR3HardenedError(VINF_SUCCESS, false,
-                                       "supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
-                                       pName->Length / sizeof(WCHAR), pName->Buffer,
-                                       pUniStrResult->Length / sizeof(WCHAR), pUniStrResult->Buffer);
-                    RtlFreeUnicodeString(&UniStrDynamic);
-                    SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
-                    return STATUS_NAME_TOO_LONG;
-                }
-                memcpy(&wszPath[0], pUniStrResult->Buffer, pUniStrResult->Length);
-                wszPath[cwc] = '\0';
+                SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", rcNt));
+                RtlRestoreLastWin32Error(dwSavedLastError);
+                return rcNt;
             }
-            RtlFreeUnicodeString(&UniStrDynamic);
         }
         else
         {
@@ -1728,21 +1906,17 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
              * Search for the DLL.  Only System32 is allowed as the target of
              * a search on the API level, all VBox calls will have full paths.
              */
-            cwc = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath) - 32);
-            if (!cwc)
-            {
-                supR3HardenedError(VINF_SUCCESS, false,
-                                   "supR3HardenedMonitor_LdrLoadDll: GetSystemDirectoryW failed: %u\n", GetLastError());
-                SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_UNEXPECTED_IO_ERROR));
-                return STATUS_UNEXPECTED_IO_ERROR;
-            }
+            AssertCompile(sizeof(g_System32WinPath.awcBuffer) <= sizeof(wszPath));
+            cwc = g_System32WinPath.UniStr.Length / sizeof(RTUTF16); Assert(cwc > 2);
             if (cwc + 1 + cwcName + fNeedDllSuffix * 4 >= RT_ELEMENTS(wszPath))
             {
                 supR3HardenedError(VINF_SUCCESS, false,
                                    "supR3HardenedMonitor_LdrLoadDll: Name too long (system32): %.*ls\n", cwcName, pawcName);
                 SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_NAME_TOO_LONG));
+                RtlRestoreLastWin32Error(dwSavedLastError);
                 return STATUS_NAME_TOO_LONG;
             }
+            memcpy(wszPath, g_System32WinPath.UniStr.Buffer, cwc * sizeof(RTUTF16));
             wszPath[cwc++] = '\\';
             memcpy(&wszPath[cwc], pawcName, cwcName * sizeof(WCHAR));
             cwc += cwcName;
@@ -1772,9 +1946,37 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
          * the real API as we've replaced any searchable name with a full name
          * and the real API can come up with a fitting status code for it.
          */
-        HANDLE hFile = CreateFileW(wszPath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
-                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
-        if (hFile != INVALID_HANDLE_VALUE)
+        HANDLE          hRootDir;
+        UNICODE_STRING  NtPathUniStr;
+        int rc = RTNtPathFromWinUtf16Ex(&NtPathUniStr, &hRootDir, wszPath, RTSTR_MAX);
+        if (RT_FAILURE(rc))
+        {
+            supR3HardenedError(rc, false,
+                               "supR3HardenedMonitor_LdrLoadDll: RTNtPathFromWinUtf16Ex failed on '%ls': %Rrc\n", wszPath, rc);
+            SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x\n", STATUS_OBJECT_NAME_INVALID));
+            RtlRestoreLastWin32Error(dwSavedLastError);
+            return STATUS_OBJECT_NAME_INVALID;
+        }
+
+        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+        OBJECT_ATTRIBUTES   ObjAttr;
+        InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
+
+        rcNt = NtCreateFile(&hFile,
+                            FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
+                            &ObjAttr,
+                            &Ios,
+                            NULL /* Allocation Size*/,
+                            FILE_ATTRIBUTE_NORMAL,
+                            FILE_SHARE_READ,
+                            FILE_OPEN,
+                            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                            NULL /*EaBuffer*/,
+                            0 /*EaLength*/);
+        if (NT_SUCCESS(rcNt))
+            rcNt = Ios.Status;
+        if (NT_SUCCESS(rcNt))
         {
             ULONG fAccess = 0;
             ULONG fProtect = 0;
@@ -1791,6 +1993,7 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
                                        wszPath, rcNt);
                     SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
                 }
+                RtlRestoreLastWin32Error(dwSavedLastError);
                 return rcNt;
             }
 
@@ -1798,142 +2001,187 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
         }
         else
         {
-            DWORD dwErr = GetLastError();
-            SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u\n", wszPath, dwErr));
+            DWORD dwErr = RtlGetLastWin32Error();
+            SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u (NtPath=%.*ls)\n",
+                         wszPath, dwErr, NtPathUniStr.Length / sizeof(RTUTF16), NtPathUniStr.Buffer));
         }
+        RTNtPathFree(&NtPathUniStr, &hRootDir);
     }
 
     /*
      * Screened successfully enough.  Call the real thing.
      */
-    SetLastError(dwSavedLastError);
+    SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
+                 (unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
+                 !((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
+    RtlRestoreLastWin32Error(dwSavedLastError);
     rcNt = g_pfnLdrLoadDllReal(pwszSearchPath, pfFlags, pName, phMod);
 
     /*
      * Log the result and process pending WinVerifyTrust work if we can.
      */
-    dwSavedLastError = GetLastError();
+    dwSavedLastError = RtlGetLastWin32Error();
 
     if (NT_SUCCESS(rcNt) && phMod)
         SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath));
     else
         SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x '%ls'\n", rcNt, wszPath));
+
     supR3HardenedWinVerifyCacheProcessWvtTodos();
 
-    SetLastError(dwSavedLastError);
+    RtlRestoreLastWin32Error(dwSavedLastError);
 
     return rcNt;
 }
 
 
-#ifdef RT_ARCH_AMD64
 /**
- * Tries to allocate memory between @a uStart and @a uEnd.
+ * DLL load and unload notification callback.
+ *
+ * This is a safety against our LdrLoadDll hook being replaced by protection
+ * software.  Though, we prefer the LdrLoadDll hook to this one as it allows us
+ * to call WinVerifyTrust more freely.
  *
- * @returns Pointer to the memory on success.  NULL on failure.
- * @param   uStart              The start address.
- * @param   uEnd                The end address.  This is lower than @a uStart
- *                              if @a iDirection is negative, and higher if
- *                              positive.
- * @param   iDirection          The search direction.
- * @param   cbAlloc             The number of bytes to allocate.
+ * @param   ulReason    The reason we're called, see
+ *                      LDR_DLL_NOTIFICATION_REASON_XXX.
+ * @param   pData       Reason specific data.  (Format is currently the same for
+ *                      both load and unload.)
+ * @param   pvUser      User parameter (ignored).
+ *
+ * @remarks Vista and later.
+ * @remarks The loader lock is held when we're called, at least on Windows 7.
  */
-static void *supR3HardenedWinAllocHookMemory(uintptr_t uStart, uintptr_t uEnd, intptr_t iDirection, size_t cbAlloc)
+static VOID CALLBACK supR3HardenedDllNotificationCallback(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser)
 {
-    size_t const cbAllocGranularity    = _64K;
-    size_t const uAllocGranularityMask = ~(cbAllocGranularity - 1);
-    HANDLE const hProc                 = NtCurrentProcess();
+    NOREF(pvUser);
 
     /*
-     * Make uEnd the last valid return address.
+     * Screen the image on load.  We will normally get a verification cache
+     * hit here because of the LdrLoadDll and NtCreateSection hooks, so it
+     * should be relatively cheap to recheck.  In case our NtDll patches
+     * got re
+     *
+     * This ASSUMES that we get informed after the fact as indicated by the
+     * available documentation.
      */
-    if (iDirection > 0)
+    if (ulReason == LDR_DLL_NOTIFICATION_REASON_LOADED)
     {
-        SUPR3HARDENED_ASSERT(uEnd > cbAlloc);
-        uEnd -= cbAlloc;
-        uEnd &= uAllocGranularityMask;
-    }
-    else
-        uEnd = RT_ALIGN_Z(uEnd, cbAllocGranularity);
+        SUP_DPRINTF(("supR3HardenedDllNotificationCallback: load   %p LB %#010x %.*ls [fFlags=%#x]\n",
+                     pData->Loaded.DllBase, pData->Loaded.SizeOfImage,
+                     pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+                     pData->Loaded.Flags));
+
+        /* Convert the windows path to an NT path and open it. */
+        HANDLE          hRootDir;
+        UNICODE_STRING  NtPathUniStr;
+        int rc = RTNtPathFromWinUtf16Ex(&NtPathUniStr, &hRootDir, pData->Loaded.FullDllName->Buffer,
+                                        pData->Loaded.FullDllName->Length / sizeof(WCHAR));
+        if (RT_FAILURE(rc))
+        {
+            supR3HardenedFatal("supR3HardenedDllNotificationCallback: RTNtPathFromWinUtf16Ex failed on '%.*ls': %Rrc\n",
+                               pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer, rc);
+            return;
+        }
+
+        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+        OBJECT_ATTRIBUTES   ObjAttr;
+        InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
+
+        NTSTATUS rcNt = NtCreateFile(&hFile,
+                                     FILE_READ_DATA | READ_CONTROL | SYNCHRONIZE,
+                                     &ObjAttr,
+                                     &Ios,
+                                     NULL /* Allocation Size*/,
+                                     FILE_ATTRIBUTE_NORMAL,
+                                     FILE_SHARE_READ,
+                                     FILE_OPEN,
+                                     FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                                     NULL /*EaBuffer*/,
+                                     0 /*EaLength*/);
+        if (NT_SUCCESS(rcNt))
+            rcNt = Ios.Status;
+        if (!NT_SUCCESS(rcNt))
+        {
+            supR3HardenedFatal("supR3HardenedDllNotificationCallback: NtCreateFile failed on '%.*ls' / '%.*ls': %#x\n",
+                               pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+                               NtPathUniStr.Length / sizeof(WCHAR), NtPathUniStr.Buffer, rcNt);
+            RTNtPathFree(&NtPathUniStr, &hRootDir);
+            return;
+        }
 
+        /* Do the screening. */
+        ULONG fAccess = 0;
+        ULONG fProtect = 0;
+        bool  fCallRealApi = false;
+        bool  fQuietFailure = false;
+        rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, &fAccess, &fProtect, &fCallRealApi,
+                                        "LdrLoadDll", true /*fAvoidWinVerifyTrust*/, &fQuietFailure);
+        NtClose(hFile);
+        if (!NT_SUCCESS(rcNt))
+        {
+            supR3HardenedFatal("supR3HardenedDllNotificationCallback: supR3HardenedScreenImage failed on '%.*ls' / '%.*ls': %#x\n",
+                               pData->Loaded.FullDllName->Length / sizeof(WCHAR), pData->Loaded.FullDllName->Buffer,
+                               NtPathUniStr.Length / sizeof(WCHAR), NtPathUniStr.Buffer, rcNt);
+            RTNtPathFree(&NtPathUniStr, &hRootDir);
+            return;
+        }
+        RTNtPathFree(&NtPathUniStr, &hRootDir);
+    }
     /*
-     * Search for free memory.
+     * Log the unload call.
      */
-    uintptr_t uCur = uStart & uAllocGranularityMask;
-    for (;;)
+    else if (ulReason == LDR_DLL_NOTIFICATION_REASON_UNLOADED)
     {
-        /*
-         * Examine the memory at this address, if it's free, try make the allocation here.
-         */
-        SIZE_T                      cbIgn;
-        MEMORY_BASIC_INFORMATION    MemInfo;
-        SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryVirtualMemory(hProc,
-                                                             (void *)uCur,
-                                                             MemoryBasicInformation,
-                                                             &MemInfo,
-                                                             sizeof(MemInfo),
-                                                             &cbIgn));
-        if (   MemInfo.State      == MEM_FREE
-            && MemInfo.RegionSize >= cbAlloc)
-        {
-            for (;;)
-            {
-                SUPR3HARDENED_ASSERT((uintptr_t)MemInfo.BaseAddress <= uCur);
+        SUP_DPRINTF(("supR3HardenedDllNotificationCallback: Unload %p LB %#010x %.*ls [flags=%#x]\n",
+                     pData->Unloaded.DllBase, pData->Unloaded.SizeOfImage,
+                     pData->Unloaded.FullDllName->Length / sizeof(WCHAR), pData->Unloaded.FullDllName->Buffer,
+                     pData->Unloaded.Flags));
+    }
+    /*
+     * Just log things we don't know and then return without caching anything.
+     */
+    else
+    {
+        static uint32_t s_cLogEntries = 0;
+        if (s_cLogEntries++ < 32)
+            SUP_DPRINTF(("supR3HardenedDllNotificationCallback: ulReason=%u pData=%p\n", ulReason, pData));
+        return;
+    }
 
-                PVOID    pvMem = (PVOID)uCur;
-                SIZE_T   cbMem = cbAlloc;
-                NTSTATUS rcNt = NtAllocateVirtualMemory(hProc, &pvMem, 0 /*ZeroBits*/, &cbAlloc,
-                                                        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
-                if (NT_SUCCESS(rcNt))
-                {
-                    if (  iDirection > 0
-                        ?    (uintptr_t)pvMem >= uStart
-                          && (uintptr_t)pvMem <= uEnd
-                        :    (uintptr_t)pvMem >= uEnd
-                          && (uintptr_t)pvMem <= uStart)
-                        return pvMem;
-                    NtFreeVirtualMemory(hProc, &pvMem, &cbMem, MEM_RELEASE);
-                }
+    /*
+     * Use this opportunity to make sure our NtDll patches are still in place,
+     * since they may be replaced by indecent protection software solutions.
+     */
+    supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+}
 
-                /* Advance within the free area and try again? */
-                uintptr_t uNext = iDirection > 0 ? uCur + cbAllocGranularity : uCur - cbAllocGranularity;
-                uNext &= uAllocGranularityMask;
-                if (  iDirection > 0
-                    ?    uNext <= uCur
-                      || uNext >  uEnd
-                      || uNext - (uintptr_t)MemInfo.BaseAddress > MemInfo.RegionSize
-                      || MemInfo.RegionSize - (uNext - (uintptr_t)MemInfo.BaseAddress) < cbAlloc
-                    :    uNext >= uCur
-                      || uNext <  uEnd
-                      || uNext <  (uintptr_t)MemInfo.BaseAddress)
-                    break;
-                uCur = uNext;
-            }
-        }
 
-        /*
-         * Advance to the next memory region.
-         */
-        if (iDirection > 0)
+/**
+ * Registers the DLL notification callback if it hasn't already been registered.
+ */
+static void supR3HardenedWinRegisterDllNotificationCallback(void)
+{
+    /*
+     * The notification API was added in Vista, so it's an optional (weak) import.
+     */
+    if (   LdrRegisterDllNotification != NULL
+        && g_cDllNotificationRegistered <= 0
+        && g_cDllNotificationRegistered > -32)
+    {
+        NTSTATUS rcNt = LdrRegisterDllNotification(0, supR3HardenedDllNotificationCallback, NULL, &g_pvDllNotificationCookie);
+        if (NT_SUCCESS(rcNt))
         {
-            uCur = (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize;
-            uCur = RT_ALIGN_Z(uCur, cbAllocGranularity);
-            if (uCur >= uEnd)
-                break;
+            SUP_DPRINTF(("Registered Dll notification callback with NTDLL.\n"));
+            g_cDllNotificationRegistered = 1;
         }
         else
         {
-            uCur = (uintptr_t)(MemInfo.AllocationBase ? MemInfo.AllocationBase : MemInfo.BaseAddress);
-            if (uCur > uEnd)
-                uCur -= cbAlloc;
-            uCur &= uAllocGranularityMask;
-            if (uCur < uEnd)
-                break;
+            supR3HardenedError(rcNt, false /*fFatal*/, "LdrRegisterDllNotification failed: %#x\n", rcNt);
+            g_cDllNotificationRegistered--;
         }
     }
-    return NULL;
 }
-#endif
 
 
 static void supR3HardenedWinHookFailed(const char *pszWhich, uint8_t const *pbPrologue)
@@ -2053,49 +2301,146 @@ DECLHIDDEN(void) supR3HardenedWinCreateParentWatcherThread(HMODULE hVBoxRT)
 
 
 /**
- * Install hooks for intercepting calls dealing with mapping shared libraries
- * into the process.
+ * Checks if the calling thread is the only one in the process.
  *
- * This allows us to prevent undesirable shared libraries from being loaded.
+ * @returns true if we're positive we're alone, false if not.
+ */
+static bool supR3HardenedWinAmIAlone(void)
+{
+    ULONG    fAmIAlone = 0;
+    ULONG    cbIgn     = 0;
+    NTSTATUS rcNt = NtQueryInformationThread(NtCurrentThread(), ThreadAmILastThread, &fAmIAlone, sizeof(fAmIAlone), &cbIgn);
+    Assert(NT_SUCCESS(rcNt));
+    return NT_SUCCESS(rcNt) && fAmIAlone != 0;
+}
+
+
+/**
+ * Simplify NtProtectVirtualMemory interface.
  *
- * @remarks We assume we're alone in this process, so no seralizing trickery is
- *          necessary when installing the patch.
+ * Modifies protection for the current process.  Caller must know the current
+ * protection as it's not returned.
  *
- * @remarks We would normally just copy the prologue sequence somewhere and add
- *          a jump back at the end of it. But because we wish to avoid
- *          allocating executable memory, we need to have preprepared assembly
- *          "copies".  This makes the non-system call patching a little tedious
- *            and inflexible.
+ * @returns NT status code.
+ * @param   pvMem               The memory to change protection for.
+ * @param   cbMem               The amount of memory to change.
+ * @param   fNewProt            The new protection.
  */
-DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
+static NTSTATUS supR3HardenedWinProtectMemory(PVOID pvMem, SIZE_T cbMem, ULONG fNewProt)
 {
-    NTSTATUS rcNt;
+    ULONG fOldProt = 0;
+    return NtProtectVirtualMemory(NtCurrentProcess(), &pvMem, &cbMem, fNewProt, &fOldProt);
+}
 
-#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
-    /*
-     * Install a anti debugging hack before we continue.  This prevents most
-     * notifications from ending up in the debugger. (Also applied to the
-     * child process when respawning.)
-     */
-    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
-    if (!NT_SUCCESS(rcNt))
-        supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
-                              "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
-#endif
 
-    /*
-     * Disable hard error popups so we can quietly refuse images to be loaded.
-     */
-    ULONG fHardErr = 0;
-    rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
-    if (!NT_SUCCESS(rcNt))
-        supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
-                              "NtQueryInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
-    if (fHardErr & PROCESS_HARDERR_CRITICAL_ERROR)
+/**
+ * Installs or reinstalls the NTDLL patches.
+ */
+static void supR3HardenedWinReInstallHooks(bool fFirstCall)
+{
+    struct
     {
-        fHardErr &= ~PROCESS_HARDERR_CRITICAL_ERROR;
-        rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
-        if (!NT_SUCCESS(rcNt))
+        size_t          cbPatch;
+        uint8_t const  *pabPatch;
+        uint8_t       **ppbApi;
+        const char     *pszName;
+    } const s_aPatches[] =
+    {
+        { sizeof(g_abNtCreateSectionPatch), g_abNtCreateSectionPatch, &g_pbNtCreateSection, "NtCreateSection" },
+        { sizeof(g_abLdrLoadDllPatch),      g_abLdrLoadDllPatch,      &g_pbLdrLoadDll,      "LdrLoadDll"      },
+    };
+
+    ULONG fAmIAlone = ~(ULONG)0;
+
+    for (uint32_t i = 0; i < RT_ELEMENTS(s_aPatches); i++)
+    {
+        uint8_t *pbApi = *s_aPatches[i].ppbApi;
+        if (memcmp(pbApi, s_aPatches[i].pabPatch, s_aPatches[i].cbPatch) != 0)
+        {
+            /*
+             * Log the incident if it's not the initial call.
+             */
+            static uint32_t volatile s_cTimes = 0;
+            if (!fFirstCall && s_cTimes < 128)
+            {
+                s_cTimes++;
+                SUP_DPRINTF(("supR3HardenedWinReInstallHooks: Reinstalling %s (%p: %.*Rhxs).\n",
+                             s_aPatches[i].pszName, pbApi, s_aPatches[i].cbPatch, pbApi));
+            }
+
+            Assert(s_aPatches[i].cbPatch >= 4);
+
+            SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READWRITE));
+
+            /*
+             * If we're alone, just memcpy the patch in.
+             */
+
+            if (fAmIAlone == ~(ULONG)0)
+                fAmIAlone = supR3HardenedWinAmIAlone();
+            if (fAmIAlone)
+                memcpy(pbApi, s_aPatches[i].pabPatch, s_aPatches[i].cbPatch);
+            else
+            {
+                /*
+                 * Not alone.  Start by injecting a JMP $-2, then waste some
+                 * CPU cycles to get the other threads a good chance of getting
+                 * out of the code before we replace it.
+                 */
+                RTUINT32U uJmpDollarMinus;
+                uJmpDollarMinus.au8[0] = 0xeb;
+                uJmpDollarMinus.au8[1] = 0xfe;
+                uJmpDollarMinus.au8[2] = pbApi[2];
+                uJmpDollarMinus.au8[3] = pbApi[3];
+                ASMAtomicXchgU32((uint32_t volatile *)pbApi, uJmpDollarMinus.u);
+
+                NtYieldExecution();
+                NtYieldExecution();
+
+                /* Copy in the tail bytes of the patch, then xchg the jmp $-2. */
+                if (s_aPatches[i].cbPatch > 4)
+                    memcpy(&pbApi[4], &s_aPatches[i].pabPatch[4], s_aPatches[i].cbPatch - 4);
+                ASMAtomicXchgU32((uint32_t volatile *)pbApi, *(uint32_t *)s_aPatches[i].pabPatch);
+            }
+
+            SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READ));
+        }
+    }
+}
+
+
+/**
+ * Install hooks for intercepting calls dealing with mapping shared libraries
+ * into the process.
+ *
+ * This allows us to prevent undesirable shared libraries from being loaded.
+ *
+ * @remarks We assume we're alone in this process, so no seralizing trickery is
+ *          necessary when installing the patch.
+ *
+ * @remarks We would normally just copy the prologue sequence somewhere and add
+ *          a jump back at the end of it. But because we wish to avoid
+ *          allocating executable memory, we need to have preprepared assembly
+ *          "copies".  This makes the non-system call patching a little tedious
+ *            and inflexible.
+ */
+static void supR3HardenedWinInstallHooks(void)
+{
+    NTSTATUS rcNt;
+
+    /*
+     * Disable hard error popups so we can quietly refuse images to be loaded.
+     */
+    ULONG fHardErr = 0;
+    rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
+                              "NtQueryInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
+    if (fHardErr & PROCESS_HARDERR_CRITICAL_ERROR)
+    {
+        fHardErr &= ~PROCESS_HARDERR_CRITICAL_ERROR;
+        rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
+        if (!NT_SUCCESS(rcNt))
             supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
                                   "NtSetInformationProcess/ProcessDefaultHardErrorMode failed: %#x\n", rcNt);
     }
@@ -2103,36 +2448,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
     /*
      * Locate the routines first so we can allocate memory that's near enough.
      */
-    HMODULE hmodNtDll = GetModuleHandleW(L"NTDLL");
-    SUPR3HARDENED_ASSERT(hmodNtDll != NULL);
-
-    FARPROC pfnNtCreateSection = GetProcAddress(hmodNtDll, "NtCreateSection");
+    PFNRT pfnNtCreateSection = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "NtCreateSection");
     SUPR3HARDENED_ASSERT(pfnNtCreateSection != NULL);
     //SUPR3HARDENED_ASSERT(pfnNtCreateSection == (FARPROC)NtCreateSection);
 
-    FARPROC pfnLdrLoadDll = GetProcAddress(hmodNtDll, "LdrLoadDll");
+    PFNRT pfnLdrLoadDll = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "LdrLoadDll");
     SUPR3HARDENED_ASSERT(pfnLdrLoadDll != NULL);
     //SUPR3HARDENED_ASSERT(pfnLdrLoadDll == (FARPROC)LdrLoadDll);
 
-
-#ifdef RT_ARCH_AMD64
     /*
-     * For 64-bit hosts we need some memory within a +/-2GB range of the
-     * actual function to be able to patch it.
+     * Exec page setup & management.
      */
-    uintptr_t uStart = RT_MAX((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
-    size_t    cbMem  = _4K;
-    void  *pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart - _2G + PAGE_SIZE, -1, cbMem);
-    if (!pvMem)
-    {
-        uintptr_t uStart = RT_MIN((uintptr_t)pfnNtCreateSection, (uintptr_t)pfnLdrLoadDll);
-        pvMem = supR3HardenedWinAllocHookMemory(uStart, uStart + _2G - PAGE_SIZE, 1, cbMem);
-        if (!pvMem)
-            supR3HardenedFatalMsg("supR3HardenedWinInstallHooks", kSupInitOp_Misc, VERR_NO_MEMORY,
-                                  "Failed to allocate memory within the +/-2GB range from NTDLL.\n");
-    }
-    uintptr_t *puJmpTab = (uintptr_t *)pvMem;
-#endif
+    uint32_t offExecPage = 0;
+    memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE);
 
     /*
      * Hook #1 - NtCreateSection.
@@ -2140,14 +2468,15 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
      *          it's mapped and we still have a file handle to work with.
      */
     uint8_t * const pbNtCreateSection = (uint8_t *)(uintptr_t)pfnNtCreateSection;
+    g_pbNtCreateSection = pbNtCreateSection;
+    memcpy(g_abNtCreateSectionPatch, pbNtCreateSection, sizeof(g_abNtCreateSectionPatch));
+
+    g_pfnNtCreateSectionReal = NtCreateSection; /* our direct syscall */
 
 #ifdef RT_ARCH_AMD64
     /*
      * Patch 64-bit hosts.
      */
-    PFNRT       pfnCallReal = NULL;
-    uint8_t     offJmpBack  = UINT8_MAX;
-
     /* Pattern #1: XP64/W2K3-64 thru Windows 8.1
        0:000> u ntdll!NtCreateSection
        ntdll!NtCreateSection:
@@ -2157,53 +2486,18 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
        00000000`779f175a c3              ret
        00000000`779f175b 0f1f440000      nop     dword ptr [rax+rax]
        The variant is the value loaded into eax: W2K3=??, Vista=47h?, W7=47h, W80=48h, W81=49h */
-    if (   pbNtCreateSection[ 0] == 0x4c /* mov r10, rcx */
-        && pbNtCreateSection[ 1] == 0x8b
-        && pbNtCreateSection[ 2] == 0xd1
-        && pbNtCreateSection[ 3] == 0xb8 /* mov eax, 000000xxh */
-        && pbNtCreateSection[ 5] == 0x00
-        && pbNtCreateSection[ 6] == 0x00
-        && pbNtCreateSection[ 7] == 0x00
-        && pbNtCreateSection[ 8] == 0x0f /* syscall */
-        && pbNtCreateSection[ 9] == 0x05
-        && pbNtCreateSection[10] == 0xc3 /* ret */
-
-/* b8 22 35 ed 0 48 63 c0 ff e0 c3 f 1f 44 0 0 - necros2 - agnitum firewall? */
-       )
-    {
-        offJmpBack = 8; /* the 3rd instruction (syscall). */
-        switch (pbNtCreateSection[4])
-        {
-# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
-# include "NtCreateSection-template-amd64-syscall-type-1.h"
-# undef SYSCALL
-        }
-    }
-    if (!pfnCallReal)
-        supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
-
-    g_pfnNtCreateSectionJmpBack         = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
-    *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal;
-    *puJmpTab                           = (uintptr_t)supR3HardenedMonitor_NtCreateSection;
 
-    DWORD dwOldProt;
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
-                                                        PAGE_EXECUTE_READWRITE, &dwOldProt));
-    pbNtCreateSection[0] = 0xff;
-    pbNtCreateSection[1] = 0x25;
-    *(uint32_t *)&pbNtCreateSection[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbNtCreateSection[2+4]);
-
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
-                                                        PAGE_EXECUTE_READ, &dwOldProt));
-    puJmpTab++;
+    /* Assemble the patch. */
+    g_abNtCreateSectionPatch[0]  = 0x48; /* mov rax, qword */
+    g_abNtCreateSectionPatch[1]  = 0xb8;
+    *(uint64_t *)&g_abNtCreateSectionPatch[2] = (uint64_t)supR3HardenedMonitor_NtCreateSection;
+    g_abNtCreateSectionPatch[10] = 0xff; /* jmp rax */
+    g_abNtCreateSectionPatch[11] = 0xe0;
 
 #else
     /*
      * Patch 32-bit hosts.
      */
-    PFNRT       pfnCallReal = NULL;
-    uint8_t     offJmpBack  = UINT8_MAX;
-
     /* Pattern #1: XP thru Windows 7
             kd> u ntdll!NtCreateSection
             ntdll!NtCreateSection:
@@ -2223,55 +2517,13 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
             6a15eac9 8bd4            mov     edx,esp
             6a15eacb 0f34            sysenter
             6a15eacd c3              ret
-       The variable bit is the value loaded into eax: W81=154h
-       Note! One nice thing here is that we can share code pattern #1.  */
-
-    if (   pbNtCreateSection[ 0] == 0xb8 /* mov eax, 000000xxh*/
-        && pbNtCreateSection[ 2] <= 0x02
-        && pbNtCreateSection[ 3] == 0x00
-        && pbNtCreateSection[ 4] == 0x00
-        && (   (   pbNtCreateSection[ 5] == 0xba /* mov edx, offset SharedUserData!SystemCallStub */
-                && pbNtCreateSection[ 6] == 0x00
-                && pbNtCreateSection[ 7] == 0x03
-                && pbNtCreateSection[ 8] == 0xfe
-                && pbNtCreateSection[ 9] == 0x7f
-                && pbNtCreateSection[10] == 0xff /* call [edx] */
-                && pbNtCreateSection[11] == 0x12
-                && pbNtCreateSection[12] == 0xc2 /* ret 1ch */
-                && pbNtCreateSection[13] == 0x1c
-                && pbNtCreateSection[14] == 0x00)
-
-            || (   pbNtCreateSection[ 5] == 0xe8 /* call [$+3] */
-                && RT_ABS(*(int32_t *)&pbNtCreateSection[6]) < 0x10
-                && pbNtCreateSection[10] == 0xc2 /* ret 1ch */
-                && pbNtCreateSection[11] == 0x1c
-                && pbNtCreateSection[12] == 0x00 )
-          )
-       )
-    {
-        offJmpBack = 5; /* the 2nd instruction. */
-        switch (*(uint32_t const *)&pbNtCreateSection[1])
-        {
-# define SYSCALL(a_Num) case a_Num: pfnCallReal = RT_CONCAT(supR3HardenedJmpBack_NtCreateSection_,a_Num); break;
-# include "NtCreateSection-template-x86-syscall-type-1.h"
-# undef SYSCALL
-        }
-    }
-    if (!pfnCallReal)
-        supR3HardenedWinHookFailed("NtCreateSection", pbNtCreateSection);
-
-    g_pfnNtCreateSectionJmpBack         = (PFNRT)(uintptr_t)(pbNtCreateSection + offJmpBack);
-    *(PFNRT *)&g_pfnNtCreateSectionReal = pfnCallReal;
+       The variable bit is the value loaded into eax: W81=154h */
 
-    DWORD dwOldProt;
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
-                                                        PAGE_EXECUTE_READWRITE, &dwOldProt));
-    pbNtCreateSection[0] = 0xe9;
-    *(uint32_t *)&pbNtCreateSection[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection
-                                       - (uintptr_t)&pbNtCreateSection[1+4];
+    /* Assemble the patch. */
+    g_abNtCreateSectionPatch[0] = 0xe9;  /* jmp rel32 */
+    *(uint32_t *)&g_abNtCreateSectionPatch[1] = (uintptr_t)supR3HardenedMonitor_NtCreateSection
+                                              - (uintptr_t)&pbNtCreateSection[1+4];
 
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbNtCreateSection, 16,
-                                                        PAGE_EXECUTE_READ, &dwOldProt));
 #endif
 
     /*
@@ -2284,165 +2536,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
      * we're at the mercy of the compiler.
      */
     uint8_t * const pbLdrLoadDll = (uint8_t *)(uintptr_t)pfnLdrLoadDll;
-    uint32_t        offExecPage  = 0;
-    memset(g_abSupHardReadWriteExecPage, 0xcc, PAGE_SIZE);
+    g_pbLdrLoadDll = pbLdrLoadDll;
+    memcpy(g_abLdrLoadDllPatch, pbLdrLoadDll, sizeof(g_abLdrLoadDllPatch));
+
+    DISSTATE Dis;
+    uint32_t cbInstr;
+    uint32_t offJmpBack = 0;
 
 #ifdef RT_ARCH_AMD64
     /*
      * Patch 64-bit hosts.
      */
-# if 0
-    /* Pattern #1:
-         Windows 8.1:
-            0:000> u ntdll!LdrLoadDll
-            ntdll!LdrLoadDll:
-            00007ffa`814ccd44 488bc4          mov     rax,rsp
-            00007ffa`814ccd47 48895808        mov     qword ptr [rax+8],rbx
-            00007ffa`814ccd4b 48896810        mov     qword ptr [rax+10h],rbp
-            00007ffa`814ccd4f 48897018        mov     qword ptr [rax+18h],rsi
-            00007ffa`814ccd53 48897820        mov     qword ptr [rax+20h],rdi
-            00007ffa`814ccd57 4156            push    r14
-            00007ffa`814ccd59 4883ec70        sub     rsp,70h
-            00007ffa`814ccd5d f6059cd2100009  test    byte ptr [ntdll!LdrpDebugFlags (00007ffa`815da000)],9
-     */
-    if (   pbLdrLoadDll[0] == 0x48 /* mov rax,rsp */
-        && pbLdrLoadDll[1] == 0x8b
-        && pbLdrLoadDll[2] == 0xc4
-        && pbLdrLoadDll[3] == 0x48 /* mov qword ptr [rax+8],rbx */
-        && pbLdrLoadDll[4] == 0x89
-        && pbLdrLoadDll[5] == 0x58
-        && pbLdrLoadDll[6] == 0x08)
-    {
-        offJmpBack = 7; /* the 3rd instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
-    }
-    /*
-       Pattern #2:
-         Windows 8.0:
-            0:000> u ntdll_w8_64!LdrLoadDll
-            ntdll_w8_64!LdrLoadDll:
-            00007ffa`52ffa7c0 48895c2408      mov     qword ptr [rsp+8],rbx
-            00007ffa`52ffa7c5 4889742410      mov     qword ptr [rsp+10h],rsi
-            00007ffa`52ffa7ca 48897c2418      mov     qword ptr [rsp+18h],rdi
-            00007ffa`52ffa7cf 55              push    rbp
-            00007ffa`52ffa7d0 4156            push    r14
-            00007ffa`52ffa7d2 4157            push    r15
-            00007ffa`52ffa7d4 488bec          mov     rbp,rsp
-            00007ffa`52ffa7d7 4883ec60        sub     rsp,60h
-            00007ffa`52ffa7db 8b05df321000    mov     eax,dword ptr [ntdll_w8_64!LdrpDebugFlags (00007ffa`530fdac0)]
-            00007ffa`52ffa7e1 4d8bf1          mov     r14,r9
-
-     */
-    else if (   pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+8],rbx */
-             && pbLdrLoadDll[1] == 0x89
-             && pbLdrLoadDll[2] == 0x5c
-             && pbLdrLoadDll[3] == 0x24
-             && pbLdrLoadDll[4] == 0x08
-             && pbLdrLoadDll[5] == 0x48 /* mov qword ptr [rsp+10h],rsi */
-             && pbLdrLoadDll[6] == 0x89
-             && pbLdrLoadDll[7] == 0x74
-             && pbLdrLoadDll[8] == 0x24
-             && pbLdrLoadDll[9] == 0x10)
-    {
-        offJmpBack = 10; /* the 3rd instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
-    }
-    /*
-       Pattern #3:
-         Windows 7:
-            ntdll_w7_64!LdrLoadDll:
-            00000000`58be4a20 48895c2410      mov     qword ptr [rsp+10h],rbx
-            00000000`58be4a25 48896c2418      mov     qword ptr [rsp+18h],rbp
-            00000000`58be4a2a 56              push    rsi
-            00000000`58be4a2b 57              push    rdi
-            00000000`58be4a2c 4154            push    r12
-            00000000`58be4a2e 4883ec50        sub     rsp,50h
-            00000000`58be4a32 f605976e100009  test    byte ptr [ntdll_w7_64!ShowSnaps (00000000`58ceb8d0)],9
-            00000000`58be4a39 498bf1          mov     rsi,r9
-
-     */
-    else if (   pbLdrLoadDll[0] == 0x48 /* mov qword ptr [rsp+10h],rbx */
-             && pbLdrLoadDll[1] == 0x89
-             && pbLdrLoadDll[2] == 0x5c
-             && pbLdrLoadDll[3] == 0x24
-             && pbLdrLoadDll[4] == 0x10)
-    {
-        offJmpBack = 5; /* the 2nd instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type3;
-    }
-    /*
-       Pattern #4:
-         Windows Vista:
-            0:000> u ntdll_vista_64!LdrLoadDll
-            ntdll_vista_64!LdrLoadDll:
-            00000000`58c11f60 fff3            push    rbx
-            00000000`58c11f62 56              push    rsi
-            00000000`58c11f63 57              push    rdi
-            00000000`58c11f64 4154            push    r12
-            00000000`58c11f66 4155            push    r13
-            00000000`58c11f68 4156            push    r14
-            00000000`58c11f6a 4157            push    r15
-            00000000`58c11f6c 4881ecb0020000  sub     rsp,2B0h
-            00000000`58c11f73 488b05367b0e00  mov     rax,qword ptr [ntdll_vista_64!_security_cookie (00000000`58cf9ab0)]
-            00000000`58c11f7a 4833c4          xor     rax,rsp
-            00000000`58c11f7d 48898424a0020000 mov     qword ptr [rsp+2A0h],rax
-
-     */
-    else if (   pbLdrLoadDll[0] == 0xff /* push rbx */
-             && pbLdrLoadDll[1] == 0xf3
-             && pbLdrLoadDll[2] == 0x56 /* push rsi */
-             && pbLdrLoadDll[3] == 0x57 /* push rdi */
-             && pbLdrLoadDll[4] == 0x41 /* push r12 */
-             && pbLdrLoadDll[5] == 0x54)
-    {
-        offJmpBack = 6; /* the 5th instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type4;
-    }
-    /*
-       Pattern #5:
-         Windows XP64:
-            0:000> u ntdll!LdrLoadDll
-            ntdll!LdrLoadDll:
-            00000000`78efa580 4c8bdc          mov     r11,rsp
-            00000000`78efa583 4881ece8020000  sub     rsp,2E8h
-            00000000`78efa58a 49895bf8        mov     qword ptr [r11-8],rbx
-            00000000`78efa58e 498973f0        mov     qword ptr [r11-10h],rsi
-            00000000`78efa592 49897be8        mov     qword ptr [r11-18h],rdi
-            00000000`78efa596 4d8963e0        mov     qword ptr [r11-20h],r12
-            00000000`78efa59a 4d896bd8        mov     qword ptr [r11-28h],r13
-            00000000`78efa59e 4d8973d0        mov     qword ptr [r11-30h],r14
-            00000000`78efa5a2 4d897bc8        mov     qword ptr [r11-38h],r15
-            00000000`78efa5a6 488b051bd10a00  mov     rax,qword ptr [ntdll!_security_cookie (00000000`78fa76c8)]
-            00000000`78efa5ad 48898424a0020000 mov     qword ptr [rsp+2A0h],rax
-            00000000`78efa5b5 4d8bf9          mov     r15,r9
-            00000000`78efa5b8 4c8bf2          mov     r14,rdx
-            00000000`78efa5bb 4c8be9          mov     r13,rcx
-            00000000`78efa5be 4c89442458      mov     qword ptr [rsp+58h],r8
-            00000000`78efa5c3 66c74424680000  mov     word ptr [rsp+68h],0
-
-     */
-    else if (   pbLdrLoadDll[0] == 0x4c /* mov r11,rsp */
-             && pbLdrLoadDll[1] == 0x8b
-             && pbLdrLoadDll[2] == 0xdc
-             && pbLdrLoadDll[3] == 0x48 /* sub rsp,2e8h */
-             && pbLdrLoadDll[4] == 0x81
-             && pbLdrLoadDll[5] == 0xec
-             && pbLdrLoadDll[6] == 0xe8
-             && pbLdrLoadDll[7] == 0x02
-             && pbLdrLoadDll[8] == 0x00
-             && pbLdrLoadDll[9] == 0x00)
-    {
-        offJmpBack = 10; /* the 3rd instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type5;
-    }
-    else
-        supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
-# else
-    /* Just use the disassembler to skip 6 bytes or more. */
-    DISSTATE Dis;
-    uint32_t cbInstr;
-    offJmpBack = 0;
-    while (offJmpBack < 6)
+    /* Just use the disassembler to skip 12 bytes or more. */
+    while (offJmpBack < 12)
     {
         cbInstr = 1;
         int rc = DISInstr(pbLdrLoadDll + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr);
@@ -2452,7 +2558,6 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
             supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
         offJmpBack += cbInstr;
     }
-# endif
 
     /* Assemble the code for resuming the call.*/
     *(PFNRT *)&g_pfnLdrLoadDllReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
@@ -2467,116 +2572,19 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
     *(uint64_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack];
     offExecPage = RT_ALIGN_32(offJmpBack + 8, 16);
 
-    /* Patch the function. */
-    *puJmpTab = (uintptr_t)supR3HardenedMonitor_LdrLoadDll;
-
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READWRITE, &dwOldProt));
-
-    Assert(offJmpBack >= 6);
-    pbLdrLoadDll[0] = 0xff;
-    pbLdrLoadDll[1] = 0x25;
-    *(uint32_t *)&pbLdrLoadDll[2] = (uint32_t)((uintptr_t)puJmpTab - (uintptr_t)&pbLdrLoadDll[2+4]);
-
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
-    puJmpTab++;
+    /* Assemble the LdrLoadDll patch. */
+    Assert(offJmpBack >= 12);
+    g_abLdrLoadDllPatch[0]  = 0x48; /* mov rax, qword */
+    g_abLdrLoadDllPatch[1]  = 0xb8;
+    *(uint64_t *)&g_abLdrLoadDllPatch[2] = (uint64_t)supR3HardenedMonitor_LdrLoadDll;
+    g_abLdrLoadDllPatch[10] = 0xff; /* jmp rax */
+    g_abLdrLoadDllPatch[11] = 0xe0;
 
 #else
     /*
      * Patch 32-bit hosts.
      */
-# if 0
-    /* Pattern #1:
-          Windows 7:
-            0:000> u ntdll!LdrLoadDll
-            ntdll!LdrLoadDll:
-            77aff585 8bff            mov     edi,edi
-            77aff587 55              push    ebp
-            77aff588 8bec            mov     ebp,esp
-            77aff58a 51              push    ecx
-            77aff58b 51              push    ecx
-            77aff58c a1f8bdaf77      mov     eax,dword ptr [ntdll!LdrpLogLevelStateTable+0x24 (77afbdf8)]
-
-          Windows 8 rtm:
-            0:000:x86> u ntdll_67150000!LdrLoadDll
-            ntdll_67150000!LdrLoadDll:
-            67189f3f 8bff            mov     edi,edi
-            67189f41 55              push    ebp
-            67189f42 8bec            mov     ebp,esp
-            67189f44 8b0d10eb2467    mov     ecx,dword ptr [ntdll_67150000!LdrpDebugFlags (6724eb10)]
-
-          Windows 8.1:
-            0:000:x86> u ntdll_w81_32!LdrLoadDll
-            ntdll_w81_32!LdrLoadDll:
-            6718aade 8bff            mov     edi,edi
-            6718aae0 55              push    ebp
-            6718aae1 8bec            mov     ebp,esp
-            6718aae3 83ec14          sub     esp,14h
-            6718aae6 f6050040246709  test    byte ptr [ntdll_w81_32!LdrpDebugFlags (67244000)],9
-
-       Pattern #2:
-          Windows XP:
-            0:000:x86> u ntdll_xp!LdrLoadDll
-            ntdll_xp!LdrLoadDll:
-            77f569d2 6858020000      push    258h
-            77f569d7 68d866f777      push    offset ntdll_xp!`string'+0x12c (77f766d8)
-            77f569dc e83bb20200      call    ntdll_xp!_SEH_prolog (77f81c1c)
-            77f569e1 33db            xor     ebx,ebx
-            77f569e3 66895de0        mov     word ptr [ebp-20h],bx
-            77f569e7 33c0            xor     eax,eax
-            77f569e9 8d7de2          lea     edi,[ebp-1Eh]
-            77f569ec ab              stos    dword ptr es:[edi]
-
-          Windows Server 2003:
-            0:000:x86> u ntdll_w2k3_32!LdrLoadDll
-            ntdll_w2k3_32!LdrLoadDll:
-            7c833f63 6840020000      push    240h
-            7c833f68 68b040837c      push    offset ntdll_w2k3_32!`string'+0x12c (7c8340b0)
-            7c833f6d e8a942ffff      call    ntdll_w2k3_32!_SEH_prolog (7c82821b)
-            7c833f72 a13077887c      mov     eax,dword ptr [ntdll_w2k3_32!__security_cookie (7c887730)]
-            7c833f77 8945e4          mov     dword ptr [ebp-1Ch],eax
-            7c833f7a 8b4508          mov     eax,dword ptr [ebp+8]
-            7c833f7d 8985b0fdffff    mov     dword ptr [ebp-250h],eax
-            7c833f83 8b450c          mov     eax,dword ptr [ebp+0Ch]
-
-          Windows Vista SP0 & SP1:
-            0:000:x86> u ntdll_vista_sp0_32!LdrLoadDll
-            ntdll_vista_sp0_32!LdrLoadDll:
-            69b0eb00 6844020000      push    244h
-            69b0eb05 6838e9b269      push    offset ntdll_vista_sp0_32! ?? ::FNODOBFM::`string'+0x39e (69b2e938)
-            69b0eb0a e835420300      call    ntdll_vista_sp0_32!_SEH_prolog4_GS (69b42d44)
-            69b0eb0f 8b4508          mov     eax,dword ptr [ebp+8]
-            69b0eb12 8985acfdffff    mov     dword ptr [ebp-254h],eax
-            69b0eb18 8b450c          mov     eax,dword ptr [ebp+0Ch]
-            69b0eb1b 8985c0fdffff    mov     dword ptr [ebp-240h],eax
-            69b0eb21 8b4510          mov     eax,dword ptr [ebp+10h]
-         */
-
-    if (   pbLdrLoadDll[0] == 0x8b /* mov edi, edi - for hot patching */
-        && pbLdrLoadDll[1] == 0xff
-        && pbLdrLoadDll[2] == 0x55 /* push ebp */
-        && pbLdrLoadDll[3] == 0x8b /* mov  ebp,esp */
-        && pbLdrLoadDll[4] == 0xec)
-    {
-        offJmpBack = 5; /* the 3rd instruction. */
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type1;
-    }
-    else if (pbLdrLoadDll[0] == 0x68 /* push dword XXXXXXXX */)
-    {
-        offJmpBack = 5;
-        pfnCallReal = supR3HardenedJmpBack_LdrLoadDll_Type2;
-        g_supR3HardenedJmpBack_LdrLoadDll_Type2_PushDword = *(uint32_t const *)&pbLdrLoadDll[1];
-    }
-    else
-        supR3HardenedWinHookFailed("LdrLoadDll", pbLdrLoadDll);
-
-    g_pfnLdrLoadDllJmpBack = (PFNRT)(uintptr_t)(pbLdrLoadDll + offJmpBack);
-    *(PFNRT *)&g_pfnLdrLoadDllReal = pfnCallReal;
-
-# else
-    /* Just use the disassembler to skip 6 bytes or more. */
-    DISSTATE Dis;
-    uint32_t cbInstr;
-    offJmpBack = 0;
+    /* Just use the disassembler to skip 5 bytes or more. */
     while (offJmpBack < 5)
     {
         cbInstr = 1;
@@ -2593,125 +2601,310 @@ DECLHIDDEN(void) supR3HardenedWinInstallHooks(void)
     memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbLdrLoadDll, offJmpBack);
     offExecPage += offJmpBack;
 
-    g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9;
+    g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9; /* jmp rel32 */
     *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbLdrLoadDll[offJmpBack]
                                                             - (uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage + 4];
     offExecPage = RT_ALIGN_32(offJmpBack + 4, 16);
 
-# endif
-
-    /* Patch LdrLoadDLl. */
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16,
-                                                        PAGE_EXECUTE_READWRITE, &dwOldProt));
+    /* Assemble the LdrLoadDll patch. */
+    memcpy(g_abLdrLoadDllPatch, pbLdrLoadDll, sizeof(g_abLdrLoadDllPatch));
     Assert(offJmpBack >= 5);
-    pbLdrLoadDll[0] = 0xe9;
-    *(uint32_t *)&pbLdrLoadDll[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
-
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), pbLdrLoadDll, 16, PAGE_EXECUTE_READ, &dwOldProt));
+    g_abLdrLoadDllPatch[0] = 0xe9;
+    *(uint32_t *)&g_abLdrLoadDllPatch[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
 #endif
 
     /*
      * Seal the rwx page.
      */
-    SUPR3HARDENED_ASSERT_WIN32_SUCCESS(VirtualProtectEx(NtCurrentProcess(), g_abSupHardReadWriteExecPage, PAGE_SIZE,
-                                                        PAGE_EXECUTE_READ, &dwOldProt));
-}
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(g_abSupHardReadWriteExecPage, PAGE_SIZE, PAGE_EXECUTE_READ));
 
-
-/**
- * Verifies the process integrity.
- */
-DECLHIDDEN(void) supR3HardenedWinVerifyProcess(void)
-{
-    RTErrInfoInitStatic(&g_ErrInfoStatic);
-    int rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(),
-                                         SUPHARDNTVPKIND_VERIFY_ONLY, NULL /*pcFixes*/, &g_ErrInfoStatic.Core);
-    if (RT_FAILURE(rc))
-        supR3HardenedFatalMsg("supR3HardenedWinVerifyProcess", kSupInitOp_Integrity, rc,
-                              "Failed to verify process integrity: %s", g_ErrInfoStatic.szMsg);
+    /*
+     * Install the patches.
+     */
+    supR3HardenedWinReInstallHooks(true /*fFirstCall*/);
 }
 
 
-/**
- * Gets the SID of the user associated with the process.
- *
- * @returns @c true if we've got a login SID, @c false if not.
- * @param   pSidUser            Where to return the user SID.
- * @param   cbSidUser           The size of the user SID buffer.
- * @param   pSidLogin           Where to return the login SID.
- * @param   cbSidLogin          The size of the login SID buffer.
- */
-static bool supR3HardenedGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
-{
-    HANDLE hToken;
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));
-    union
-    {
-        TOKEN_USER      UserInfo;
-        TOKEN_GROUPS    Groups;
-        uint8_t         abPadding[4096];
-    } uBuf;
-    ULONG cbRet = 0;
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidUser, pSidUser, uBuf.UserInfo.User.Sid));
 
-    bool fLoginSid = false;
-    NTSTATUS rcNt = NtQueryInformationToken(hToken, TokenLogonSid, &uBuf, sizeof(uBuf), &cbRet);
-    if (NT_SUCCESS(rcNt))
-    {
-        for (DWORD i = 0; i < uBuf.Groups.GroupCount; i++)
-            if ((uBuf.Groups.Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
-            {
-                SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidLogin, pSidLogin, uBuf.Groups.Groups[i].Sid));
-                fLoginSid = true;
-                break;
-            }
-    }
 
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hToken));
 
-    return fLoginSid;
-}
+
+/*
+ *
+ * T h r e a d   c r e a t i o n   c o n t r o l
+ * T h r e a d   c r e a t i o n   c o n t r o l
+ * T h r e a d   c r e a t i o n   c o n t r o l
+ *
+ */
 
 
 /**
- * Build security attributes for the process or the primary thread (@a fProcess)
+ * Common code used for child and parent to make new threads exit immediately.
  *
- * Process DACLs can be bypassed using the SeDebugPrivilege (generally available
- * to admins, i.e. normal windows users), or by taking ownership and/or
- * modifying the DACL.  However, it restricts
+ * This patches the LdrInitializeThunk code to call NtTerminateThread with
+ * STATUS_SUCCESS instead of doing the NTDLL initialization.
  *
- * @param   pSecAttrs           Where to return the security attributes.
- * @param   pCleanup            Cleanup record.
- * @param   fProcess            Set if it's for the process, clear if it's for
- *                              the primary thread.
+ * @returns VBox status code.
+ * @param   hProcess            The process to do this to.
+ * @param   pvLdrInitThunk      The address of the LdrInitializeThunk code to
+ *                              override.
+ * @param   pvNtTerminateThread The address of the NtTerminateThread function in
+ *                              the NTDLL instance we're patching.  (Must be +/-
+ *                              2GB from the thunk code.)
+ * @param   pabBackup           Where to back up the original instruction bytes
+ *                              at pvLdrInitThunk.
+ * @param   cbBackup            The size of the backup area. Must be 16 bytes.
+ * @param   pErrInfo            Where to return extended error information.
+ *                              Optional.
  */
-static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
+static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
+                                              uint8_t *pabBackup, size_t cbBackup, PRTERRINFO pErrInfo)
 {
+    SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
+    SUPR3HARDENED_ASSERT(cbBackup == 16);
+    SUPR3HARDENED_ASSERT(RT_ABS((intptr_t)pvLdrInitThunk - (intptr_t)pvNtTerminateThread) < 16*_1M);
+
     /*
-     * Safe return values.
+     * Back up the thunk code.
      */
-    suplibHardenedMemSet(pCleanup, 0, sizeof(*pCleanup));
+    SIZE_T  cbIgnored;
+    NTSTATUS rcNt = NtReadVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtDisableThreadCreation: NtReadVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
 
-    pSecAttrs->nLength              = sizeof(*pSecAttrs);
-    pSecAttrs->bInheritHandle       = FALSE;
-    pSecAttrs->lpSecurityDescriptor = NULL;
+    /*
+     * Cook up replacement code that calls NtTerminateThread.
+     */
+    uint8_t abReplacement[16];
+    memcpy(abReplacement, pabBackup, sizeof(abReplacement));
 
-/** @todo This isn't at all complete, just sketches... */
+#ifdef RT_ARCH_AMD64
+    abReplacement[0] = 0x31;    /* xor ecx, ecx */
+    abReplacement[1] = 0xc9;
+    abReplacement[2] = 0x31;    /* xor edx, edx */
+    abReplacement[3] = 0xd2;
+    abReplacement[4] = 0xe8;    /* call near NtTerminateThread */
+    *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
+    abReplacement[9] = 0xcc;    /* int3 */
+#elif defined(RT_ARCH_X86)
+    abReplacement[0] = 0x6a;    /* push 0 */
+    abReplacement[1] = 0x00;
+    abReplacement[2] = 0x6a;    /* push 0 */
+    abReplacement[3] = 0x00;
+    abReplacement[4] = 0xe8;    /* call near NtTerminateThread */
+    *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
+    abReplacement[9] = 0xcc;    /* int3 */
+#else
+# error "Unsupported arch."
+#endif
 
     /*
-     * Create an ACL detailing the access of the above groups.
+     * Install the replacment code.
      */
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
+    PVOID  pvProt   = pvLdrInitThunk;
+    SIZE_T cbProt   = cbBackup;
+    ULONG  fOldProt = 0;
+    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
 
-    ULONG fDeny  = DELETE | WRITE_DAC | WRITE_OWNER;
-    ULONG fAllow = SYNCHRONIZE | READ_CONTROL;
-    ULONG fAllowLogin = SYNCHRONIZE | READ_CONTROL;
-    if (fProcess)
-    {
-        fDeny       |= PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
-                    |  PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA
-                    |  PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
+    rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtDisableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+
+    pvProt   = pvLdrInitThunk;
+    cbProt   = cbBackup;
+    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Undo the effects of supR3HardNtDisableThreadCreationEx.
+ *
+ * @returns VBox status code.
+ * @param   hProcess            The process to do this to.
+ * @param   pvLdrInitThunk      The address of the LdrInitializeThunk code to
+ *                              override.
+ * @param   pabBackup           Where to back up the original instruction bytes
+ *                              at pvLdrInitThunk.
+ * @param   cbBackup            The size of the backup area. Must be 16 bytes.
+ * @param   pErrInfo            Where to return extended error information.
+ *                              Optional.
+ */
+static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
+                                             PRTERRINFO pErrInfo)
+{
+    SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
+    SUPR3HARDENED_ASSERT(cbBackup == 16);
+
+    PVOID  pvProt   = pvLdrInitThunk;
+    SIZE_T cbProt   = cbBackup;
+    ULONG  fOldProt = 0;
+    NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+
+    SIZE_T cbIgnored;
+    rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
+                             rcNt);
+
+    pvProt   = pvLdrInitThunk;
+    cbProt   = cbBackup;
+    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
+                             "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
+                             rcNt);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Disable thread creation for the current process.
+ *
+ * @remarks Doesn't really disables it, just makes the threads exit immediately
+ *          without executing any real code.
+ */
+static void supR3HardenedWinDisableThreadCreation(void)
+{
+    /* Cannot use the imported NtTerminateThread as it's pointing to our own
+       syscall assembly code. */
+    static PFNRT s_pfnNtTerminateThread = NULL;
+    if (s_pfnNtTerminateThread == NULL)
+        s_pfnNtTerminateThread = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "NtTerminateThread");
+    SUPR3HARDENED_ASSERT(s_pfnNtTerminateThread);
+
+    int rc = supR3HardNtDisableThreadCreationEx(NtCurrentProcess(),
+                                                (void *)(uintptr_t)&LdrInitializeThunk,
+                                                (void *)(uintptr_t)s_pfnNtTerminateThread,
+                                                g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
+                                                NULL /* pErrInfo*/);
+    g_fSupInitThunkSelfPatched = RT_SUCCESS(rc);
+}
+
+
+/**
+ * Undoes the effects of supR3HardenedWinDisableThreadCreation.
+ */
+DECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void)
+{
+    if (g_fSupInitThunkSelfPatched)
+    {
+        int rc = supR3HardNtEnableThreadCreationEx(NtCurrentProcess(),
+                                                   (void *)(uintptr_t)&LdrInitializeThunk,
+                                                   g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
+                                                   RTErrInfoInitStatic(&g_ErrInfoStatic));
+        if (RT_FAILURE(rc))
+            supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
+        g_fSupInitThunkSelfPatched = false;
+    }
+}
+
+
+
+
+/*
+ *
+ * R e s p a w n
+ * R e s p a w n
+ * R e s p a w n
+ *
+ */
+
+
+/**
+ * Gets the SID of the user associated with the process.
+ *
+ * @returns @c true if we've got a login SID, @c false if not.
+ * @param   pSidUser            Where to return the user SID.
+ * @param   cbSidUser           The size of the user SID buffer.
+ * @param   pSidLogin           Where to return the login SID.
+ * @param   cbSidLogin          The size of the login SID buffer.
+ */
+static bool supR3HardNtChildGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
+{
+    HANDLE hToken;
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));
+    union
+    {
+        TOKEN_USER      UserInfo;
+        TOKEN_GROUPS    Groups;
+        uint8_t         abPadding[4096];
+    } uBuf;
+    ULONG cbRet = 0;
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidUser, pSidUser, uBuf.UserInfo.User.Sid));
+
+    bool fLoginSid = false;
+    NTSTATUS rcNt = NtQueryInformationToken(hToken, TokenLogonSid, &uBuf, sizeof(uBuf), &cbRet);
+    if (NT_SUCCESS(rcNt))
+    {
+        for (DWORD i = 0; i < uBuf.Groups.GroupCount; i++)
+            if ((uBuf.Groups.Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
+            {
+                SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCopySid(cbSidLogin, pSidLogin, uBuf.Groups.Groups[i].Sid));
+                fLoginSid = true;
+                break;
+            }
+    }
+
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hToken));
+
+    return fLoginSid;
+}
+
+
+/**
+ * Build security attributes for the process or the primary thread (@a fProcess)
+ *
+ * Process DACLs can be bypassed using the SeDebugPrivilege (generally available
+ * to admins, i.e. normal windows users), or by taking ownership and/or
+ * modifying the DACL.  However, it restricts
+ *
+ * @param   pSecAttrs           Where to return the security attributes.
+ * @param   pCleanup            Cleanup record.
+ * @param   fProcess            Set if it's for the process, clear if it's for
+ *                              the primary thread.
+ */
+static void supR3HardNtChildInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
+{
+    /*
+     * Safe return values.
+     */
+    suplibHardenedMemSet(pCleanup, 0, sizeof(*pCleanup));
+
+    pSecAttrs->nLength              = sizeof(*pSecAttrs);
+    pSecAttrs->bInheritHandle       = FALSE;
+    pSecAttrs->lpSecurityDescriptor = NULL;
+
+/** @todo This isn't at all complete, just sketches... */
+
+    /*
+     * Create an ACL detailing the access of the above groups.
+     */
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
+
+    ULONG fDeny  = DELETE | WRITE_DAC | WRITE_OWNER;
+    ULONG fAllow = SYNCHRONIZE | READ_CONTROL;
+    ULONG fAllowLogin = SYNCHRONIZE | READ_CONTROL;
+    if (fProcess)
+    {
+        fDeny       |= PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
+                    |  PROCESS_CREATE_PROCESS | PROCESS_DUP_HANDLE | PROCESS_SET_QUOTA
+                    |  PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
         fAllow      |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
         fAllowLogin |= PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION;
         if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
@@ -2759,8 +2952,8 @@ static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURIT
 #endif
 
 #if 1
-    bool fHasLoginSid = supR3HardenedGetUserAndLogSids(&pCleanup->User.Sid, sizeof(pCleanup->User),
-                                                       &pCleanup->Login.Sid, sizeof(pCleanup->Login));
+    bool fHasLoginSid = supR3HardNtChildGetUserAndLogSids(&pCleanup->User.Sid, sizeof(pCleanup->User),
+                                                          &pCleanup->Login.Sid, sizeof(pCleanup->Login));
 
 # if 1
     /* Grant minimal access to the user. */
@@ -2784,7 +2977,7 @@ static void supR3HardenedInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURIT
     /*
      * Create a security descriptor with the above ACL.
      */
-    PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)suplibHardenedAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
+    PSECURITY_DESCRIPTOR pSecDesc = (PSECURITY_DESCRIPTOR)RTMemAllocZ(SECURITY_DESCRIPTOR_MIN_LENGTH);
     pCleanup->pSecDesc = pSecDesc;
 
     SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
@@ -2830,7 +3023,7 @@ DECLINLINE(bool) suplibCommandLineIsArgSeparator(int ch)
  * @param   iWhich          Which respawn we're to check for, 1 being the first
  *                          one, and 2 the second and final.
  */
-static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iWhich)
+static PRTUTF16 supR3HardNtChildConstructCmdLine(PUNICODE_STRING pString, int iWhich)
 {
     SUPR3HARDENED_ASSERT(iWhich == 1 || iWhich == 2);
 
@@ -2883,10 +3076,10 @@ static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iW
     size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_1_ARG0) - 1) / sizeof(SUPR3_RESPAWN_1_ARG0[0]) /* Respawn exe name. */
                       + !!cwcArgs + cwcArgs; /* if arguments present, add space + arguments. */
     if (cwcCmdLine * sizeof(WCHAR) >= 0xfff0)
-        supR3HardenedFatalMsg("supR3HardenedWinConstructCmdLine", kSupInitOp_Misc, VERR_OUT_OF_RANGE,
+        supR3HardenedFatalMsg("supR3HardNtChildConstructCmdLine", kSupInitOp_Misc, VERR_OUT_OF_RANGE,
                               "Command line is too long (%u chars)!", cwcCmdLine);
 
-    PRTUTF16 pwszCmdLine = (PRTUTF16)HeapAlloc(GetProcessHeap(), 0 /* dwFlags*/, (cwcCmdLine + 1) * sizeof(RTUTF16));
+    PRTUTF16 pwszCmdLine = (PRTUTF16)RTMemAlloc((cwcCmdLine + 1) * sizeof(RTUTF16));
     SUPR3HARDENED_ASSERT(pwszCmdLine != NULL);
 
     /*
@@ -2917,565 +3110,630 @@ static PRTUTF16 supR3HardenedWinConstructCmdLine(PUNICODE_STRING pString, int iW
 
 
 /**
- * Check if the zero terminated NT unicode string is the path to the given
- * system32 DLL.
+ * Terminates the child process.
  *
- * @returns true if it is, false if not.
- * @param   pUniStr             The zero terminated NT unicode string path.
- * @param   pszName             The name of the system32 DLL.
+ * @param   hProcess            The process handle.
+ * @param   pszWhere            Who's having child rasing troubles.
+ * @param   rc                  The status code to report.
+ * @param   pszFormat           The message format string.
+ * @param   ...                 Message format arguments.
  */
-static bool supR3HardNtIsNamedSystem32Dll(PUNICODE_STRING pUniStr, const char *pszName)
+static void supR3HardenedWinKillChild(HANDLE hProcess, const char *pszWhere, int rc, const char *pszFormat, ...)
 {
-    if (pUniStr->Length > g_System32NtPath.UniStr.Length)
+    /*
+     * Terminate the process ASAP and display error.
+     */
+    NtTerminateProcess(hProcess, RTEXITCODE_FAILURE);
+
+    va_list va;
+    va_start(va, pszFormat);
+    supR3HardenedErrorV(rc, false /*fFatal*/, pszFormat, va);
+    va_end(va);
+
+    /*
+     * Wait for the process to really go away.
+     */
+    PROCESS_BASIC_INFORMATION BasicInfo;
+    NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+    bool fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
+    if (!fExitOk)
     {
-        if (memcmp(pUniStr->Buffer, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
+        NTSTATUS rcNtWait;
+        uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+        do
         {
-            if (pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR)] == '\\')
-            {
-                if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
-                    return true;
-            }
-        }
+            NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
+
+            LARGE_INTEGER Timeout;
+            Timeout.QuadPart = -20000000; /* 2 second */
+            rcNtWait = NtWaitForSingleObject(hProcess, TRUE /*Alertable*/, &Timeout);
+
+            rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+            fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
+        } while (   !fExitOk
+                 && (   rcNtWait == STATUS_TIMEOUT
+                     || rcNtWait == STATUS_USER_APC
+                     || rcNtWait == STATUS_ALERTED)
+                 && supR3HardenedWinGetMilliTS() - uMsTsStart < 60 * 1000);
+        if (fExitOk)
+            supR3HardenedError(rc, false /*fFatal*/,
+                               "NtDuplicateObject failed and we failed to kill child: rc=%u (%#x) rcNtWait=%#x hProcess=%p\n",
+                               rc, rc, rcNtWait, hProcess);
     }
 
-    return false;
+    /*
+     * Final error message.
+     */
+    va_start(va, pszFormat);
+    supR3HardenedFatalMsgV(pszWhere, kSupInitOp_Misc, rc, pszFormat, va);
+    va_end(va);
 }
 
 
 /**
- * Common code used for child and parent to make new threads exit immediately.
+ * Checks the child process when hEvtParent is signalled.
  *
- * This patches the LdrInitializeThunk code to call NtTerminateThread with
- * STATUS_SUCCESS instead of doing the NTDLL initialization.
+ * This will read the request data from the child and check it against expected
+ * request.  If an error is signalled, we'll raise it and make sure the child
+ * terminates before terminating the calling process.
  *
- * @returns VBox status code.
- * @param   hProcess            The process to do this to.
- * @param   pvLdrInitThunk      The address of the LdrInitializeThunk code to
- *                              override.
- * @param   pvNtTerminateThread The address of the NtTerminateThread function in
- *                              the NTDLL instance we're patching.  (Must be +/-
- *                              2GB from the thunk code.)
- * @param   pabBackup           Where to back up the original instruction bytes
- *                              at pvLdrInitThunk.
- * @param   cbBackup            The size of the backup area. Must be 16 bytes.
- * @param   pErrInfo            Where to return extended error information.
- *                              Optional.
+ * @param   pThis               The child process data structure.
+ * @param   enmExpectedRequest  The expected child request.
+ * @param   pszWhat             What we're waiting for.
  */
-static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
-                                              uint8_t *pabBackup, size_t cbBackup, PRTERRINFO pErrInfo)
+static void supR3HardNtChildProcessRequest(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, const char *pszWhat)
 {
-    SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
-    SUPR3HARDENED_ASSERT(cbBackup == 16);
-    SUPR3HARDENED_ASSERT(RT_ABS((intptr_t)pvLdrInitThunk - (intptr_t)pvNtTerminateThread) < 16*_1M);
+    /*
+     * Read the process parameters from the child.
+     */
+    uintptr_t           uChildAddr = (uintptr_t)pThis->Peb.ImageBaseAddress
+                                   + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
+    SIZE_T              cbIgnored  = 0;
+    RT_ZERO(pThis->ProcParams);
+    NTSTATUS rcNt = NtReadVirtualMemory(pThis->hProcess, (PVOID)uChildAddr,
+                                        &pThis->ProcParams, sizeof(pThis->ProcParams), &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildProcessRequest", rcNt,
+                                  "NtReadVirtualMemory(,%p,) failed reading child process status: %#x\n", uChildAddr, rcNt);
 
     /*
-     * Back up the thunk code.
+     * Is it the expected request?
      */
-    SIZE_T  cbIgnored;
-    NTSTATUS rcNt = NtReadVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
+    if (pThis->ProcParams.enmRequest == enmExpectedRequest)
+        return;
+
+    /*
+     * No, not the expected request. If it's an error request, tell the child
+     * to terminate itself, otherwise we'll have to terminate it.
+     */
+    pThis->ProcParams.szErrorMsg[sizeof(pThis->ProcParams.szErrorMsg) - 1] = '\0';
+    pThis->ProcParams.szWhere[sizeof(pThis->ProcParams.szWhere) - 1] = '\0';
+    SUP_DPRINTF(("supR3HardenedWinCheckChild: enmRequest=%d rc=%d enmWhat=%d %s: %s\n",
+                 pThis->ProcParams.enmRequest, pThis->ProcParams.rc, pThis->ProcParams.enmWhat,
+                 pThis->ProcParams.szWhere, pThis->ProcParams.szErrorMsg));
+
+    if (pThis->ProcParams.enmRequest != kSupR3WinChildReq_Error)
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinCheckChild", VERR_INVALID_PARAMETER,
+                                  "Unexpected child request #%d. Was expecting #%d (%s).\n",
+                                  pThis->ProcParams.enmRequest, enmExpectedRequest, pszWhat);
+
+    rcNt = NtSetEvent(pThis->hEvtChild, NULL);
     if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtDisableThreadCreation: NtReadVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildProcessRequest", rcNt, "NtSetEvent failed: %#x\n", rcNt);
+
+    /* Wait for it to terminate. */
+    LARGE_INTEGER Timeout;
+    Timeout.QuadPart = -50000000; /* 5 seconds */
+    rcNt = NtWaitForSingleObject(pThis->hProcess, FALSE /*Alertable*/, &Timeout);
+    if (rcNt != STATUS_WAIT_0)
+    {
+        SUP_DPRINTF(("supR3HardNtChildProcessRequest: Child is taking too long to quit (rcWait=%#x), killing it...\n", rcNt));
+        NtTerminateProcess(pThis->hProcess, DBG_TERMINATE_PROCESS);
+    }
 
     /*
-     * Cook up replacement code that calls NtTerminateThread.
+     * Report the error in the same way as it occured in the guest.
      */
-    uint8_t abReplacement[16];
-    memcpy(abReplacement, pabBackup, sizeof(abReplacement));
-
-#ifdef RT_ARCH_AMD64
-    abReplacement[0] = 0x31;    /* xor ecx, ecx */
-    abReplacement[1] = 0xc9;
-    abReplacement[2] = 0x31;    /* xor edx, edx */
-    abReplacement[3] = 0xd2;
-    abReplacement[4] = 0xe8;    /* call near NtTerminateThread */
-    *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
-    abReplacement[9] = 0xcc;    /* int3 */
-#elif defined(RT_ARCH_X86)
-    abReplacement[0] = 0x6a;    /* push 0 */
-    abReplacement[1] = 0x00;
-    abReplacement[2] = 0x6a;    /* push 0 */
-    abReplacement[3] = 0x00;
-    abReplacement[4] = 0xe8;    /* call near NtTerminateThread */
-    *(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
-    abReplacement[9] = 0xcc;    /* int3 */
-#else
-# error "Unsupported arch."
-#endif
-
-    /*
-     * Install the replacment code.
-     */
-    PVOID  pvProt   = pvLdrInitThunk;
-    SIZE_T cbProt   = cbBackup;
-    ULONG  fOldProt = 0;
-    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
-
-    rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtDisableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
-
-    pvProt   = pvLdrInitThunk;
-    cbProt   = cbBackup;
-    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
-
-    return VINF_SUCCESS;
-}
+    if (pThis->ProcParams.enmWhat == kSupInitOp_Invalid)
+        supR3HardenedFatalMsg("supR3HardenedWinCheckChild", kSupInitOp_Misc, pThis->ProcParams.rc,
+                              "%s", pThis->ProcParams.szErrorMsg);
+    else
+        supR3HardenedFatalMsg(pThis->ProcParams.szWhere, pThis->ProcParams.enmWhat, pThis->ProcParams.rc,
+                              "%s", pThis->ProcParams.szErrorMsg);
+}
 
 
 /**
- * Undo the effects of supR3HardNtDisableThreadCreationEx.
+ * Waits for the child to make a certain request or terminate.
  *
- * @returns VBox status code.
- * @param   hProcess            The process to do this to.
- * @param   pvLdrInitThunk      The address of the LdrInitializeThunk code to
- *                              override.
- * @param   pabBackup           Where to back up the original instruction bytes
- *                              at pvLdrInitThunk.
- * @param   cbBackup            The size of the backup area. Must be 16 bytes.
- * @param   pErrInfo            Where to return extended error information.
- *                              Optional.
+ * The stub process will also wait on it's parent to terminate.
+ * This call will only return if the child made the expected request.
+ *
+ * @param   pThis               The child process data structure.
+ * @param   enmExpectedRequest  The child request to wait for.
+ * @param   cMsTimeout          The number of milliseconds to wait (at least).
+ * @param   pszWhat             What we're waiting for.
  */
-static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
-                                             PRTERRINFO pErrInfo)
+static void supR3HardNtChildWaitFor(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, RTMSINTERVAL cMsTimeout,
+                                    const char *pszWhat)
 {
-    SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
-    SUPR3HARDENED_ASSERT(cbBackup == 16);
+    /*
+     * The wait loop.
+     * Will return when the expected request arrives.
+     * Will break out when one of the processes terminates.
+     */
+    NTSTATUS      rcNtWait;
+    LARGE_INTEGER Timeout;
+    uint64_t      uMsTsStart = supR3HardenedWinGetMilliTS();
+    uint64_t      cMsElapsed = 0;
+    for (;;)
+    {
+        /*
+         * Assemble handles to wait for.
+         */
+        ULONG  cHandles = 1;
+        HANDLE ahHandles[3];
+        ahHandles[0] = pThis->hProcess;
+        if (pThis->hEvtParent)
+            ahHandles[cHandles++] = pThis->hEvtParent;
+        if (pThis->hParent)
+            ahHandles[cHandles++] = pThis->hParent;
 
-    PVOID  pvProt   = pvLdrInitThunk;
-    SIZE_T cbProt   = cbBackup;
-    ULONG  fOldProt = 0;
-    NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
+        /*
+         * Do the waiting according to the callers wishes.
+         */
+        if (   enmExpectedRequest == kSupR3WinChildReq_End
+            || cMsTimeout  == RT_INDEFINITE_WAIT)
+            rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*Timeout*/);
+        else
+        {
+            Timeout.QuadPart = -(int64_t)(cMsTimeout - cMsElapsed) * 10000;
+            rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, &Timeout);
+        }
 
-    SIZE_T cbIgnored;
-    rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, pabBackup, cbBackup, &cbIgnored);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
-                             rcNt);
+        /*
+         * Process child request.
+         */
+        if (rcNtWait == STATUS_WAIT_0 + 1 && pThis->hEvtParent != NULL)
+        {
+            supR3HardNtChildProcessRequest(pThis, enmExpectedRequest, pszWhat);
+            SUP_DPRINTF(("supR3HardNtChildWaitFor: Found expected request %d (%s) after %llu ms.\n",
+                         enmExpectedRequest, pszWhat, supR3HardenedWinGetMilliTS() - uMsTsStart));
+            return; /* Expected request received. */
+        }
 
-    pvProt   = pvLdrInitThunk;
-    cbProt   = cbBackup;
-    rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
-                             rcNt);
+        /*
+         * Process termination?
+         */
+        if (   (ULONG)rcNtWait - (ULONG)STATUS_WAIT_0           < cHandles
+            || (ULONG)rcNtWait - (ULONG)STATUS_ABANDONED_WAIT_0 < cHandles)
+            break;
 
-    return VINF_SUCCESS;
-}
+        /*
+         * Check sanity.
+         */
+        if (   rcNtWait != STATUS_TIMEOUT
+            && rcNtWait != STATUS_USER_APC
+            && rcNtWait != STATUS_ALERTED)
+            supR3HardenedWinKillChild(pThis, "supR3HardNtChildWaitFor", rcNtWait,
+                                      "NtWaitForMultipleObjects returned %#x waiting for #%d (%s)\n",
+                                      rcNtWait, enmExpectedRequest, pszWhat);
 
+        /*
+         * Calc elapsed time for the next timeout calculation, checking to see
+         * if we've timed out already.
+         */
+        cMsElapsed = supR3HardenedWinGetMilliTS() - uMsTsStart;
+        if (   cMsElapsed > cMsTimeout
+            && cMsTimeout != RT_INDEFINITE_WAIT
+            && enmExpectedRequest != kSupR3WinChildReq_End)
+        {
+            if (rcNtWait == STATUS_USER_APC || rcNtWait == STATUS_ALERTED)
+                cMsElapsed = cMsTimeout - 1; /* try again */
+            else
+            {
+                /* We timed out. */
+                supR3HardenedWinKillChild(pThis, "supR3HardNtChildWaitFor", rcNtWait,
+                                          "Timed out after %llu ms waiting for child request #%d (%s).\n",
+                                          cMsElapsed, enmExpectedRequest, pszWhat);
+            }
+        }
+    }
 
-/**
- * Disable thread creation for the current process.
- *
- * @remarks Doesn't really disables it, just makes the threads exit immediately
- *          without executing any real code.
- */
-static void supR3HardenedWinDisableThreadCreation(void)
-{
-    /* Cannot use the imported NtTerminateThread as it's pointing to our own
-       syscall assembly code. */
-    FARPROC pfnNtTerminateThread = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtTerminateThread");
-    SUPR3HARDENED_ASSERT(pfnNtTerminateThread);
+    /*
+     * Proxy the termination code of the child, if it exited already.
+     */
+    PROCESS_BASIC_INFORMATION BasicInfo;
+    NTSTATUS rcNt1 = NtQueryInformationProcess(pThis->hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
+    NTSTATUS rcNt2 = STATUS_PENDING;
+    NTSTATUS rcNt3 = STATUS_PENDING;
+    if (   !NT_SUCCESS(rcNt1)
+        || BasicInfo.ExitStatus == STATUS_PENDING)
+    {
+        rcNt2 = NtTerminateProcess(pThis->hProcess, RTEXITCODE_FAILURE);
+        Timeout.QuadPart = NT_SUCCESS(rcNt2) ? -20000000 /* 2 sec */ : -1280000 /* 128 ms */;
+        rcNt3 = NtWaitForSingleObject(pThis->hProcess, FALSE /*Alertable*/, NULL /*Timeout*/);
+        BasicInfo.ExitStatus = RTEXITCODE_FAILURE;
+    }
 
-    int rc = supR3HardNtDisableThreadCreationEx(NtCurrentProcess(),
-                                                (void *)(uintptr_t)&LdrInitializeThunk,
-                                                (void *)(uintptr_t)pfnNtTerminateThread,
-                                                g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
-                                                NULL /* pErrInfo*/);
-    g_fSupInitThunkSelfPatched = RT_SUCCESS(rc);
+    SUP_DPRINTF(("supR3HardNtChildWaitFor[%d]: Quitting: ExitCode=%#x (rcNtWait=%#x, rcNt1=%#x, rcNt2=%#x, rcNt3=%#x, %llu ms, %s);\n",
+                 pThis->iWhich, BasicInfo.ExitStatus, rcNtWait, rcNt1, rcNt2, rcNt3,
+                 supR3HardenedWinGetMilliTS() - uMsTsStart, pszWhat));
+    suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
 }
 
 
 /**
- * Undoes the effects of supR3HardenedWinDisableThreadCreation.
+ * Closes full access child thread and process handles, making a harmless
+ * duplicate of the process handle first.
+ *
+ * The hProcess member of the child process data structure will be change to the
+ * harmless handle, while the hThread will be set to NULL.
+ *
+ * @param   pThis               The child process data structure.
  */
-DECLHIDDEN(void) supR3HardenedWinEnableThreadCreation(void)
+static void supR3HardNtChildCloseFullAccessHandles(PSUPR3HARDNTCHILD pThis)
 {
-    if (g_fSupInitThunkSelfPatched)
+    /*
+     * The thread handle.
+     */
+    NTSTATUS rcNt = NtClose(pThis->hThread);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", rcNt, "NtClose(hThread) failed: %#x", rcNt);
+    pThis->hThread = NULL;
+
+    /*
+     * Duplicate the process handle into a harmless one.
+     */
+    HANDLE hProcWait;
+    ULONG fRights = SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_VM_READ;
+    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
+        fRights |= PROCESS_QUERY_LIMITED_INFORMATION;
+    else
+        fRights |= PROCESS_QUERY_INFORMATION;
+    rcNt = NtDuplicateObject(NtCurrentProcess(), pThis->hProcess,
+                             NtCurrentProcess(), &hProcWait,
+                             fRights, 0 /*HandleAttributes*/, 0);
+    if (rcNt == STATUS_ACCESS_DENIED)
     {
-        int rc = supR3HardNtEnableThreadCreationEx(NtCurrentProcess(),
-                                                   (void *)(uintptr_t)&LdrInitializeThunk,
-                                                   g_abLdrInitThunkSelfBackup, sizeof(g_abLdrInitThunkSelfBackup),
-                                                   RTErrInfoInitStatic(&g_ErrInfoStatic));
-        if (RT_FAILURE(rc))
-            supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
-        g_fSupInitThunkSelfPatched = false;
+        supR3HardenedError(rcNt, false /*fFatal*/,
+                           "supR3HardenedWinDoReSpawn: NtDuplicateObject(,,,,%#x,,) -> %#x, retrying with only %#x...\n",
+                           fRights, rcNt, SYNCHRONIZE);
+        rcNt = NtDuplicateObject(NtCurrentProcess(), pThis->hProcess,
+                                 NtCurrentProcess(), &hProcWait,
+                                 SYNCHRONIZE, 0 /*HandleAttributes*/, 0);
     }
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", rcNt,
+                                  "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
+    /*
+     * Close the process handle and replace it with the harmless one.
+     */
+    rcNt = NtClose(pThis->hProcess);
+    pThis->hProcess = hProcWait;
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", VERR_INVALID_NAME,
+                                  "NtClose failed on child process handle: %#x\n", rcNt);
 }
 
 
-
-/*
- * Child-Process Purification - release it from dubious influences. 
- *  
- * AV software and other things injecting themselves into the embryonic 
- * and budding process to intercept API calls and what not.  Unfortunately 
- * this is also the behavior of viruses, malware and other unfriendly 
- * software, so we won't stand for it.  AV software can scan our image 
- * as they are loaded via kernel hooks, that's sufficient.  No need for 
- * matching half of NTDLL or messing with the import table of the 
- * process executable. 
+/**
+ * This restores the child PEB and tweaks a couple of fields before we do the
+ * child purification and let the process run normally.
+ *
+ * @param   pThis               The child process data structure.
  */
-
-typedef struct SUPR3HARDNTPUCH
-{
-    /** Process handle. */
-    HANDLE                      hProcess;
-    /** Primary thread handle. */
-    HANDLE                      hThread;
-    /** Error buffer. */
-    PRTERRINFO                  pErrInfo;
-    /** The address of NTDLL in the child. */
-    uintptr_t                   uNtDllAddr;
-    /** The address of NTDLL in this process. */
-    uintptr_t                   uNtDllParentAddr;
-    /** The basic process info. */
-    PROCESS_BASIC_INFORMATION   BasicInfo;
-    /** The probable size of the PEB. */
-    size_t                      cbPeb;
-    /** The pristine process environment block. */
-    PEB                         Peb;
-} SUPR3HARDNTPUCH;
-typedef SUPR3HARDNTPUCH *PSUPR3HARDNTPUCH;
-
-
-static int supR3HardNtPuChScrewUpPebForInitialImageEvents(PSUPR3HARDNTPUCH pThis)
+static void supR3HardNtChildSanitizePeb(PSUPR3HARDNTCHILD pThis)
 {
     /*
-     * Not sure if any of the cracker software uses the PEB at this point, but
-     * just in case they do make some of the PEB fields a little less useful.
+     * Make a copy of the pre-execution PEB.
      */
     PEB Peb = pThis->Peb;
 
-    /* Make ImageBaseAddress useless. */
-    Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress ^ UINT32_C(0x5f139000));
-#ifdef RT_ARCH_AMD64
-    Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress | UINT64_C(0x0313000000000000));
+#if 0
+    /*
+     * There should not be any activation context, so if there is, we scratch the memory associated with it.
+     */
+    int rc = 0;
+    if (RT_SUCCESS(rc) && Peb.pShimData && !((uintptr_t)Peb.pShimData & PAGE_OFFSET_MASK))
+        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.pShimData, PAGE_SIZE, "pShimData", pErrInfo);
+    if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
+        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
+    if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
+        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
+    if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
+        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
+    if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
+        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
+    if (RT_FAILURE(rc))
+        return rc;
 #endif
 
     /*
-     * Write the PEB.
+     * Clear compatibility and activation related fields.
+     */
+    Peb.AppCompatFlags.QuadPart             = 0;
+    Peb.AppCompatFlagsUser.QuadPart         = 0;
+    Peb.pShimData                           = NULL;
+    Peb.AppCompatInfo                       = NULL;
+#if 0
+    Peb.ActivationContextData               = NULL;
+    Peb.ProcessAssemblyStorageMap           = NULL;
+    Peb.SystemDefaultActivationContextData  = NULL;
+    Peb.SystemAssemblyStorageMap            = NULL;
+    /*Peb.Diff0.W6.IsProtectedProcess = 1;*/
+#endif
+
+    /*
+     * Write back the PEB.
      */
     SIZE_T cbActualMem = pThis->cbPeb;
     NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
     if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
-    return VINF_SUCCESS;
-}
-
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildSanitizePeb", rcNt,
+                                  "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
 
-/**
- * Unmaps a DLL from the child process that was previously mapped by
- * supR3HardNtPuChMapDllIntoChild.
- *
- * @returns Pointer to the DLL mapping on success, NULL on failure.
- * @param   pThis               The child purification instance data.
- * @param   pvBase              The base address of the mapping.  Nothing done
- *                              if NULL.
- * @param   pszShort            The short name (for logging).
- */
-static void supR3HardNtPuChUnmapDllFromChild(PSUPR3HARDNTPUCH pThis, PVOID pvBase, const char *pszShort)
-{
-    if (pvBase)
-    {
-        /*SUP_DPRINTF(("supR3HardNtPuChUnmapDllFromChild: Calling NtUnmapViewOfSection on %p / %s\n", pvBase, pszShort));*/
-        NTSTATUS rcNt = NtUnmapViewOfSection(pThis->hProcess, pvBase);
-        if (!NT_SUCCESS(!rcNt))
-            SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtUnmapViewOfSection failed on %s: %#x (%p)\n",
-                         pszShort, rcNt, pvBase));
-    }
 }
 
 
 /**
- * Maps a DLL into the child process.
+ * Purifies the child process after very early init has been performed.
  *
- * @returns Pointer to the DLL mapping on success, NULL on failure.
- * @param   pThis               The child purification instance data.
- * @param   pNtName             The path to the DLL.
- * @param   pszShort            The short name (for logging).
+ * @param   pThis               The child process data structure.
  */
-static PVOID supR3HardNtPuChMapDllIntoChild(PSUPR3HARDNTPUCH pThis, PUNICODE_STRING pNtName, const char *pszShort)
+static void supR3HardNtChildPurify(PSUPR3HARDNTCHILD pThis)
 {
-    HANDLE              hFile  = RTNT_INVALID_HANDLE_VALUE;
-    IO_STATUS_BLOCK     Ios    = RTNT_IO_STATUS_BLOCK_INITIALIZER;
-    OBJECT_ATTRIBUTES   ObjAttr;
-    InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
-    NTSTATUS rcNt = NtCreateFile(&hFile,
-                                 GENERIC_READ | GENERIC_EXECUTE,
-                                 &ObjAttr,
-                                 &Ios,
-                                 NULL /* Allocation Size*/,
-                                 FILE_ATTRIBUTE_NORMAL,
-                                 FILE_SHARE_READ,
-                                 FILE_OPEN,
-                                 FILE_NON_DIRECTORY_FILE,
-                                 NULL /*EaBuffer*/,
-                                 0 /*EaLength*/);
-    if (NT_SUCCESS(rcNt))
-        rcNt = Ios.Status;
-    PVOID pvRet = NULL;
-    if (NT_SUCCESS(rcNt))
+    /*
+     * We loop until we no longer make any fixes.  This is similar to what
+     * we do (or used to do, really) in the fAvastKludge case of
+     * supR3HardenedWinInit.  We might be up against asynchronous changes,
+     * which we fudge by waiting a short while before earch purification. This
+     * is arguably a fragile technique, but it's currently the best we've got.
+     * Fortunately, most AVs seems to either favor immediate action on initial
+     * load events or (much better for us) later events like kernel32.
+     */
+    uint64_t uMsTsOuterStart = supR3HardenedWinGetMilliTS();
+    uint32_t cMsFudge        = g_fSupAdversaries ? 512 : 256;
+    uint32_t cTotalFixes     = 0;
+    uint32_t cFixes;
+    for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
     {
-        HANDLE hSection = RTNT_INVALID_HANDLE_VALUE;
-        rcNt = NtCreateSection(&hSection,
-                               SECTION_MAP_EXECUTE | SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_QUERY,
-                               NULL /* pObjAttr*/, NULL /*pMaxSize*/,
-                               PAGE_EXECUTE, SEC_IMAGE, hFile);
-        if (NT_SUCCESS(rcNt))
+        /*
+         * Delay.
+         */
+        uint32_t cSleeps = 0;
+        uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+        do
         {
-            SIZE_T cbView = 0;
-            SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: mapping view of %s\n", pszShort)); /* For SEP. */
-            rcNt = NtMapViewOfSection(hSection, pThis->hProcess, &pvRet, 0 /*ZeroBits*/, 0 /*CommitSize*/,
-                                      NULL /*pOffSect*/, &cbView, ViewShare, 0 /*AllocationType*/, PAGE_READWRITE);
-            if (NT_SUCCESS(rcNt))
-                SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: %s mapped at %p LB %#x\n", pszShort, pvRet, cbView));
-            else
-            {
-                SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtMapViewOfSection failed on %s: %#x\n", pszShort, rcNt));
-                pvRet = NULL;
-            }
-            NtClose(hSection);
+            NtYieldExecution();
+            LARGE_INTEGER Time;
+            Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
+            NtDelayExecution(FALSE, &Time);
+            cSleeps++;
+        } while (   supR3HardenedWinGetMilliTS() - uMsTsStart <= cMsFudge
+                 || cSleeps < 8);
+        SUP_DPRINTF(("supR3HardNtChildPurify: Startup delay kludge #1/%u: %u ms, %u sleeps\n",
+                     iLoop, supR3HardenedWinGetMilliTS() - uMsTsStart, cSleeps));
+
+        /*
+         * Purify.
+         */
+        cFixes = 0;
+        int rc = supHardenedWinVerifyProcess(pThis->hProcess, pThis->hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION,
+                                             g_fSupAdversaries & (  SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE
+                                                                  | SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN)
+                                             ? SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW : 0,
+                                             &cFixes, RTErrInfoInitStatic(&g_ErrInfoStatic));
+        if (RT_FAILURE(rc))
+            supR3HardenedWinKillChild(pThis, "supR3HardNtChildPurify", rc,
+                                      "supHardenedWinVerifyProcess failed with %Rrc: %s", rc, g_ErrInfoStatic.szMsg);
+        if (cFixes == 0)
+        {
+            SUP_DPRINTF(("supR3HardNtChildPurify: Done after %llu ms and %u fixes (loop #%u).\n",
+                         supR3HardenedWinGetMilliTS() - uMsTsOuterStart, cTotalFixes, iLoop));
+            return; /* We're probably good. */
         }
+        cTotalFixes += cFixes;
+
+        if (!g_fSupAdversaries)
+            g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
+        cMsFudge = 512;
+
+        /*
+         * Log the KiOpPrefetchPatchCount value if available, hoping it might
+         * sched some light on spider38's case.
+         */
+        ULONG cPatchCount = 0;
+        NTSTATUS rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
+                                                 &cPatchCount, sizeof(cPatchCount), NULL);
+        if (NT_SUCCESS(rcNt))
+            SUP_DPRINTF(("supR3HardNtChildPurify: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
+                         cFixes, g_fSupAdversaries, cPatchCount));
         else
-            SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: NtCreateSection failed on %s: %#x\n", pszShort, rcNt));
-        NtClose(hFile);
+            SUP_DPRINTF(("supR3HardNtChildPurify: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
     }
-    else
-        SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Error opening %s: %#x\n", pszShort, rcNt));
-    return pvRet;
+
+    /*
+     * We've given up fixing the child process.  Probably fighting someone
+     * that monitors their patches or/and our activities.
+     */
+    supR3HardenedWinKillChild(pThis, "supR3HardNtChildPurify", VERR_TRY_AGAIN,
+                              "Unable to purify child process! After 16 tries over %llu ms, we still %u fix(es) in the last pass.",
+                              supR3HardenedWinGetMilliTS() - uMsTsOuterStart, cFixes);
 }
 
 
+
 /**
- * Trigger the initial image events without actually initializing the process.
- *
- * This is a trick to force sysplant.sys to call its hand by tripping the image
- * loaded event for the main executable and ntdll images.  This will happen when
- * the first thread in a process starts executing in PspUserThreadStartup.  We
- * create a second thread that quits immediately by means of temporarily
- * replacing ntdll!LdrInitializeThunk by a NtTerminateThread call.
- * (LdrInitializeThunk is called by way of an APC queued the thread is created,
- * thus NtSetContextThread is of no use.)
+ * Sets up the early process init.
  *
- * @returns VBox status code.
- * @param   pThis               The child cleanup
- * @param   pErrInfo            For extended error information.
+ * @param   pThis               The child process data structure.
  */
-static int supR3HardNtPuChTriggerInitialImageEvents(PSUPR3HARDNTPUCH pThis)
+static void supR3HardNtChildSetUpChildInit(PSUPR3HARDNTCHILD pThis)
 {
+    uintptr_t const uChildExeAddr = (uintptr_t)pThis->Peb.ImageBaseAddress;
+
+    /*
+     * Plant the process parameters.  This ASSUMES the handle inheritance is
+     * performed when creating the child process.
+     */
+    RT_ZERO(pThis->ProcParams);
+    pThis->ProcParams.hEvtChild  = pThis->hEvtChild;
+    pThis->ProcParams.hEvtParent = pThis->hEvtParent;
+    pThis->ProcParams.uNtDllAddr = pThis->uNtDllAddr;
+    pThis->ProcParams.enmRequest = kSupR3WinChildReq_Error;
+    pThis->ProcParams.rc         = VINF_SUCCESS;
+
+    uintptr_t uChildAddr = uChildExeAddr + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
+    SIZE_T    cbIgnored;
+    NTSTATUS  rcNt = NtWriteVirtualMemory(pThis->hProcess, (PVOID)uChildAddr, &pThis->ProcParams,
+                                          sizeof(pThis->ProcParams), &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+                                  "NtWriteVirtualMemory(,%p,) failed writing child process parameters: %#x\n", uChildAddr, rcNt);
+
     /*
-     * Use the on-disk image for the ntdll entrypoints here.
+     * Locate the LdrInitializeThunk address in the child as well as pristine
+     * code bits for it.
      */
     PSUPHNTLDRCACHEENTRY pLdrEntry;
     int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
     if (RT_FAILURE(rc))
-        return RTErrInfoSetF(pThis->pErrInfo, rc, "supHardNtLdrCacheOpen failed on NTDLL: %Rrc", rc);
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+                                  "supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
+
+    uint8_t *pbChildNtDllBits;
+    rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbChildNtDllBits, pThis->uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
+    if (RT_FAILURE(rc))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+                                  "supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
 
     RTLDRADDR uLdrInitThunk;
-    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
+    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbChildNtDllBits, pThis->uNtDllAddr, UINT32_MAX,
                           "LdrInitializeThunk", &uLdrInitThunk);
     if (RT_FAILURE(rc))
-        return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating LdrInitializeThunk in NTDLL: %Rrc", rc);
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rc,
+                                  "Error locating LdrInitializeThunk in NTDLL: %Rrc", rc);
     PVOID pvLdrInitThunk = (PVOID)(uintptr_t)uLdrInitThunk;
-
-    RTLDRADDR uNtTerminateThread;
-    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pLdrEntry->pbBits, pThis->uNtDllAddr, UINT32_MAX,
-                          "NtTerminateThread", &uNtTerminateThread);
-    if (RT_FAILURE(rc))
-        return RTErrInfoSetF(pThis->pErrInfo, rc, "Error locating NtTerminateThread in NTDLL: %Rrc", rc);
-
-    SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: uLdrInitThunk=%p uNtTerminateThread=%p\n",
-                 (uintptr_t)uLdrInitThunk, (uintptr_t)uNtTerminateThread));
+    SUP_DPRINTF(("supR3HardenedWinSetupChildInit: uLdrInitThunk=%p\n", (uintptr_t)uLdrInitThunk));
 
     /*
-     * Patch the child's LdrInitializeThunk to exit the thread immediately.
+     * Calculate the address of our code in the child process.
      */
-    uint8_t abBackup[16];
-    rc = supR3HardNtDisableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, (void *)(uintptr_t)uNtTerminateThread,
-                                            abBackup, sizeof(abBackup), pThis->pErrInfo);
-    if (RT_FAILURE(rc))
-        return rc;
+    uintptr_t uEarlyProcInitEP = uChildExeAddr + (  (uintptr_t)&supR3HardenedEarlyProcessInitThunk
+                                                  - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
 
     /*
-     * To further muddle the waters, we map the executable image and ntdll.dll
-     * a 2nd time into the process before we actually start executing the thread
-     * and trigger the genuine image load events.
-     *
-     * Update: Turns out Symantec Endpoint Protection deadlocks when we map the
-     *         executable into the process like this.  The system only works
-     *         halfways after that Powerbutton, impossible to shutdown without
-     *         using the power or reset button. The order of the two mappings
-     *         below doesn't matter. Haven't had time to look at stack yet.
-     *         Observed on W7/64, SEP v12.1.4112.4156.
-     *
+     * Compose the LdrInitializeThunk replacement bytes.
+     * Note! The amount of code we replace here must be less or equal to what
+     *       the process verification code ignores.
      */
-#if 0
-    PVOID pvExe2 = supR3HardNtPuChMapDllIntoChild(pThis, &g_SupLibHardenedExeNtPath.UniStr, "executable[2nd]");
+    uint8_t abNew[16];
+    memcpy(abNew, pbChildNtDllBits + ((uintptr_t)uLdrInitThunk - pThis->uNtDllAddr), sizeof(abNew));
+#ifdef RT_ARCH_AMD64
+    abNew[0] = 0xff;
+    abNew[1] = 0x25;
+    *(uint32_t *)&abNew[2] = 0;
+    *(uint64_t *)&abNew[6] = uEarlyProcInitEP;
+#elif defined(RT_ARCH_X86)
+    abNew[0] = 0xe9;
+    *(uint32_t *)&abNew[1] = uEarlyProcInitEP - ((uint32_t)uLdrInitThunk + 5);
 #else
-    PVOID pvExe2 = NULL;
+# error "Unsupported arch."
 #endif
-    UNICODE_STRING NtName1 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\ntdll.dll");
-    PVOID pvNtDll2 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName1, "ntdll.dll[2nd]");
-
-    /*
-     * Create the thread, waiting 10 seconds for it to complete.
-     */
-    CLIENT_ID Thread2Id;
-    HANDLE hThread2;
-    NTSTATUS rcNt = RtlCreateUserThread(pThis->hProcess,
-                                        NULL /* SecurityAttribs */,
-                                        FALSE /* CreateSuspended */,
-                                        0 /* ZeroBits */,
-                                        0 /* MaximumStackSize */,
-                                        0 /* CommittedStackSize */,
-                                        (PFNRT)2 /* StartAddress */,
-                                        NULL /*Parameter*/ ,
-                                        &hThread2,
-                                        &Thread2Id);
-    if (NT_SUCCESS(rcNt))
-    {
-        LARGE_INTEGER Timeout;
-        Timeout.QuadPart = -10 * 10000000; /* 10 seconds */
-        NtWaitForSingleObject(hThread2, FALSE /* Alertable */, &Timeout);
-        NtTerminateThread(hThread2, DBG_TERMINATE_THREAD);
-        NtClose(hThread2);
-    }
-
-    /*
-     * Map kernel32.dll and kernelbase.dll (if applicable) into the process.
-     * This triggers should image load events that may set of AV activities
-     * that we'd rather see early than later.
-     */
-    UNICODE_STRING NtName2 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\kernel32.dll");
-    PVOID pvKernel32 = supR3HardNtPuChMapDllIntoChild(pThis, &NtName2, "kernel32.dll");
-
-    UNICODE_STRING NtName3 = RTNT_CONSTANT_UNISTR(L"\\SystemRoot\\System32\\KernelBase.dll");
-    PVOID pvKernelBase = g_uNtVerCombined >= SUP_NT_VER_VISTA
-                       ? supR3HardNtPuChMapDllIntoChild(pThis, &NtName3, "KernelBase.dll")
-                       : NULL;
 
     /*
-     * Fudge factor for letting kernel threads get a chance to mess up our
-     * process asynchronously.
+     * Install the LdrInitializeThunk replacement code in the child process.
      */
-    DWORD dwStart = GetTickCount();
-    NtYieldExecution();
-
-    LARGE_INTEGER Time;
-    Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
-    NtDelayExecution(FALSE, &Time);
-
-    NtYieldExecution();
-
-    Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
-    NtDelayExecution(FALSE, &Time);
-
-    NtYieldExecution();
-    SUP_DPRINTF(("supR3HardNtPuChTriggerInitialImageEvents: Startup delay kludge #1: %u ms\n", GetTickCount() - dwStart));
+    PVOID   pvProt = pvLdrInitThunk;
+    SIZE_T  cbProt = sizeof(abNew);
+    ULONG   fOldProt;
+    rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+                                  "NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
 
-    /*
-     * Unmap the image we mapped into the guest above.
-     */
-    supR3HardNtPuChUnmapDllFromChild(pThis, pvKernel32, "kernel32.dll");
-    supR3HardNtPuChUnmapDllFromChild(pThis, pvKernelBase, "KernelBase.dll");
-    supR3HardNtPuChUnmapDllFromChild(pThis, pvNtDll2, "ntdll.dll[2nd]");
-    supR3HardNtPuChUnmapDllFromChild(pThis, pvExe2, "executable[2nd]");
+    rcNt = NtWriteVirtualMemory(pThis->hProcess, pvLdrInitThunk, abNew, sizeof(abNew), &cbIgnored);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+                                  "NtWriteVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
 
-    /*
-     * Restore the original thunk code and protection.
-     * We do this after waiting as anyone trying to kick of threads in the
-     * process will get nothing done as long as our patch is in place.
-     */
-    rc = supR3HardNtEnableThreadCreationEx(pThis->hProcess, pvLdrInitThunk, abBackup, sizeof(abBackup), pThis->pErrInfo);
-    if (RT_FAILURE(rc))
-        return rc;
+    pvProt = pvLdrInitThunk;
+    cbProt = sizeof(abNew);
+    rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, fOldProt, &fOldProt);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(pThis, "supR3HardenedWinSetupChildInit", rcNt,
+                                  "NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x", rcNt);
 
-    return VINF_SUCCESS;
+    /* Caller starts child execution. */
+    SUP_DPRINTF(("supR3HardenedWinSetupChildInit: Start child.\n"));
 }
 
-#if 0
-static int supR3HardenedWinScratchChildMemory(HANDLE hProcess, void *pv, size_t cb, const char *pszWhat, PRTERRINFO pErrInfo)
-{
-    SUP_DPRINTF(("supR3HardenedWinScratchChildMemory: %p %#x\n", pv, cb));
-
-    PVOID  pvCopy = pv;
-    SIZE_T cbCopy = cb;
-    NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvCopy, &cbCopy, PAGE_NOACCESS, NULL);
-    if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtProtectVirtualMemory/%s (%p LB %#zx) failed: %#x",
-                             pszWhat, pv, cb, rcNt);
-    return VINF_SUCCESS;
-}
-#endif
 
 
-static int supR3HardNtPuChSanitizePeb(PSUPR3HARDNTPUCH pThis)
+/**
+ * This messes with the child PEB before we trigger the initial image events.
+ *
+ * @param   pThis               The child process data structure.
+ */
+static void supR3HardNtChildScrewUpPebForInitialImageEvents(PSUPR3HARDNTCHILD pThis)
 {
     /*
-     * Make a copy of the pre-execution PEB.
+     * Not sure if any of the cracker software uses the PEB at this point, but
+     * just in case they do make some of the PEB fields a little less useful.
      */
     PEB Peb = pThis->Peb;
 
-#if 0
-    /*
-     * There should not be any activation context, so if there is, we scratch the memory associated with it.
-     */
-    int rc = 0;
-    if (RT_SUCCESS(rc) && Peb.pShimData && !((uintptr_t)Peb.pShimData & PAGE_OFFSET_MASK))
-        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.pShimData, PAGE_SIZE, "pShimData", pErrInfo);
-    if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
-        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
-    if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
-        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
-    if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
-        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
-    if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
-        rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
-    if (RT_FAILURE(rc))
-        return rc;
-#endif
-
-    /*
-     * Clear compatibility and activation related fields.
-     */
-    Peb.AppCompatFlags.QuadPart             = 0;
-    Peb.AppCompatFlagsUser.QuadPart         = 0;
-    Peb.pShimData                           = NULL;
-    Peb.AppCompatInfo                       = NULL;
-#if 0
-    Peb.ActivationContextData               = NULL;
-    Peb.ProcessAssemblyStorageMap           = NULL;
-    Peb.SystemDefaultActivationContextData  = NULL;
-    Peb.SystemAssemblyStorageMap            = NULL;
-    /*Peb.Diff0.W6.IsProtectedProcess = 1;*/
+    /* Make ImageBaseAddress useless. */
+    Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress ^ UINT32_C(0x5f139000));
+#ifdef RT_ARCH_AMD64
+    Peb.ImageBaseAddress = (PVOID)((uintptr_t)Peb.ImageBaseAddress | UINT64_C(0x0313000000000000));
 #endif
 
     /*
-     * Write back the PEB.
+     * Write the PEB.
      */
     SIZE_T cbActualMem = pThis->cbPeb;
     NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
     if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pThis->pErrInfo, VERR_GENERAL_FAILURE, "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildScrewUpPebForInitialImageEvents", rcNt,
+                                  "NtWriteVirtualMemory/Peb failed: %#x", rcNt);
+}
+
+
+/**
+ * Check if the zero terminated NT unicode string is the path to the given
+ * system32 DLL.
+ *
+ * @returns true if it is, false if not.
+ * @param   pUniStr             The zero terminated NT unicode string path.
+ * @param   pszName             The name of the system32 DLL.
+ */
+static bool supR3HardNtIsNamedSystem32Dll(PUNICODE_STRING pUniStr, const char *pszName)
+{
+    if (pUniStr->Length > g_System32NtPath.UniStr.Length)
+    {
+        if (memcmp(pUniStr->Buffer, g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length) == 0)
+        {
+            if (pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR)] == '\\')
+            {
+                if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
+                    return true;
+            }
+        }
+    }
 
-    return VINF_SUCCESS;
+    return false;
 }
 
 
-static void supR3HardNtPuChFindNtdll(PSUPR3HARDNTPUCH pThis)
+/**
+ * Worker for supR3HardNtChildGatherData that locates NTDLL in the child
+ * process.
+ *
+ * @param   pThis               The child process data structure.
+ */
+static void supR3HardNtChildFindNtdll(PSUPR3HARDNTCHILD pThis)
 {
     /*
      * Find NTDLL in this process first and take that as a starting point.
@@ -3544,65 +3802,87 @@ static void supR3HardNtPuChFindNtdll(PSUPR3HARDNTPUCH pThis)
         uPtrWhere += MemInfo.RegionSize;
     }
 
-#ifdef DEBUG
-    supR3HardenedFatal("%s: ntdll.dll not found in child.", __FUNCTION__);
-#endif
+    supR3HardenedWinKillChild(pThis, "supR3HardNtChildFindNtdll", VERR_MODULE_NOT_FOUND, "ntdll.dll not found in child process.");
 }
 
 
-
-static int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, PRTERRINFO pErrInfo)
+/**
+ * Gather child data.
+ *
+ * @param   This                The child process data structure.
+ */
+static void supR3HardNtChildGatherData(PSUPR3HARDNTCHILD pThis)
 {
     /*
-     * Initialize the purifier instance data.
+     * Basic info.
      */
-    SUPR3HARDNTPUCH This;
-    This.hProcess = hProcess;
-    This.hThread  = hThread;
-    This.pErrInfo = pErrInfo;
-
     ULONG cbActual = 0;
-    NTSTATUS rcNt = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
-                                              &This.BasicInfo, sizeof(This.BasicInfo), &cbActual);
+    NTSTATUS rcNt = NtQueryInformationProcess(pThis->hProcess, ProcessBasicInformation,
+                                              &pThis->BasicInfo, sizeof(pThis->BasicInfo), &cbActual);
     if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
-                             "NtQueryInformationProcess/ProcessBasicInformation failed: %#x", rcNt);
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildGatherData", rcNt,
+                                  "NtQueryInformationProcess/ProcessBasicInformation failed: %#x", rcNt);
+
+    /*
+     * If this is the middle (stub) process, we wish to wait for both child
+     * and parent.  So open the parent process.  Not fatal if we cannnot.
+     */
+    if (pThis->iWhich > 1)
+    {
+        PROCESS_BASIC_INFORMATION SelfInfo;
+        rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &SelfInfo, sizeof(SelfInfo), &cbActual);
+        if (NT_SUCCESS(rcNt))
+        {
+            OBJECT_ATTRIBUTES ObjAttr;
+            InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+            CLIENT_ID ClientId;
+            ClientId.UniqueProcess = (HANDLE)SelfInfo.InheritedFromUniqueProcessId;
+            ClientId.UniqueThread  = NULL;
+
+            rcNt = NtOpenProcess(&pThis->hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
+#ifdef DEBUG
+            SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
+#endif
+            if (!NT_SUCCESS(rcNt))
+            {
+                pThis->hParent = NULL;
+                SUP_DPRINTF(("supR3HardNtChildGatherData: Failed to open parent process (%#p): %#x\n", ClientId.UniqueProcess, rcNt));
+            }
+        }
 
+    }
+
+    /*
+     * Process environment block.
+     */
     if (g_uNtVerCombined < SUP_NT_VER_W2K3)
-        This.cbPeb = PEB_SIZE_W51;
+        pThis->cbPeb = PEB_SIZE_W51;
     else if (g_uNtVerCombined < SUP_NT_VER_VISTA)
-        This.cbPeb = PEB_SIZE_W52;
+        pThis->cbPeb = PEB_SIZE_W52;
     else if (g_uNtVerCombined < SUP_NT_VER_W70)
-        This.cbPeb = PEB_SIZE_W6;
+        pThis->cbPeb = PEB_SIZE_W6;
     else if (g_uNtVerCombined < SUP_NT_VER_W80)
-        This.cbPeb = PEB_SIZE_W7;
+        pThis->cbPeb = PEB_SIZE_W7;
     else if (g_uNtVerCombined < SUP_NT_VER_W81)
-        This.cbPeb = PEB_SIZE_W80;
+        pThis->cbPeb = PEB_SIZE_W80;
     else
-        This.cbPeb = PEB_SIZE_W81;
+        pThis->cbPeb = PEB_SIZE_W81;
 
-    SUP_DPRINTF(("supR3HardenedWinPurifyChild: PebBaseAddress=%p cbPeb=%#x\n", This.BasicInfo.PebBaseAddress, This.cbPeb));
+    SUP_DPRINTF(("supR3HardNtChildGatherData: PebBaseAddress=%p cbPeb=%#x\n",
+                 pThis->BasicInfo.PebBaseAddress, pThis->cbPeb));
 
     SIZE_T cbActualMem;
-    RT_ZERO(This.Peb);
-    rcNt = NtReadVirtualMemory(hProcess, This.BasicInfo.PebBaseAddress, &This.Peb, sizeof(This.Peb), &cbActualMem);
+    RT_ZERO(pThis->Peb);
+    rcNt = NtReadVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &pThis->Peb, sizeof(pThis->Peb), &cbActualMem);
     if (!NT_SUCCESS(rcNt))
-        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "NtReadVirtualMemory/Peb failed: %#x", rcNt);
-
-    supR3HardNtPuChFindNtdll(&This);
+        supR3HardenedWinKillChild(pThis, "supR3HardNtChildGatherData", rcNt,
+                                  "NtReadVirtualMemory/Peb failed: %#x", rcNt);
 
     /*
-     * Do the work, the last bit we tag along with the process verfication code.
+     * Locate NtDll.
      */
-    int rc = supR3HardNtPuChScrewUpPebForInitialImageEvents(&This);
-    if (RT_SUCCESS(rc))
-        rc = supR3HardNtPuChTriggerInitialImageEvents(&This);
-    if (RT_SUCCESS(rc))
-        rc = supR3HardNtPuChSanitizePeb(&This);
-    if (RT_SUCCESS(rc))
-        rc = supHardenedWinVerifyProcess(hProcess, hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION, NULL /*pcFixes*/, pErrInfo);
-
-    return rc;
+    supR3HardNtChildFindNtdll(pThis);
 }
 
 
@@ -3612,10 +3892,8 @@ static int supR3HardenedWinPurifyChild(HANDLE hProcess, HANDLE hThread, PRTERRIN
  * @returns Never, will call exit or raise fatal error.
  * @param   iWhich              Which respawn we're to check for, 1 being the
  *                              first one, and 2 the second and final.
- *
- * @todo    Split up this function.
  */
-static int supR3HardenedWinDoReSpawn(int iWhich)
+static void supR3HardenedWinDoReSpawn(int iWhich)
 {
     NTSTATUS                        rcNt;
     PPEB                            pPeb              = NtCurrentPeb();
@@ -3624,15 +3902,32 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
     SUPR3HARDENED_ASSERT(g_cSuplibHardenedWindowsMainCalls == 1);
 
     /*
+     * Init the child process data structure, creating the child communication
+     * event sempahores.
+     */
+    SUPR3HARDNTCHILD This;
+    RT_ZERO(This);
+    This.iWhich = iWhich;
+
+    OBJECT_ATTRIBUTES ObjAttrs;
+    This.hEvtChild = NULL;
+    InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtChild, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
+
+    This.hEvtParent = NULL;
+    InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtParent, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
+
+    /*
      * Set up security descriptors.
      */
     SECURITY_ATTRIBUTES ProcessSecAttrs;
     MYSECURITYCLEANUP   ProcessSecAttrsCleanup;
-    supR3HardenedInitSecAttrs(&ProcessSecAttrs, &ProcessSecAttrsCleanup, true /*fProcess*/);
+    supR3HardNtChildInitSecAttrs(&ProcessSecAttrs, &ProcessSecAttrsCleanup, true /*fProcess*/);
 
     SECURITY_ATTRIBUTES ThreadSecAttrs;
     MYSECURITYCLEANUP   ThreadSecAttrsCleanup;
-    supR3HardenedInitSecAttrs(&ThreadSecAttrs, &ThreadSecAttrsCleanup, false /*fProcess*/);
+    supR3HardNtChildInitSecAttrs(&ThreadSecAttrs, &ThreadSecAttrsCleanup, false /*fProcess*/);
 
 #if 1
     /*
@@ -3651,6 +3946,9 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
         /** @todo experiment with protected process stuff later on. */
     }
 
+    SiEx.StartupInfo.dwFlags |= pParentProcParams->WindowFlags & STARTF_USESHOWWINDOW;
+    SiEx.StartupInfo.wShowWindow = (WORD)pParentProcParams->ShowWindowFlags;
+
     SiEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
     SiEx.StartupInfo.hStdInput  = pParentProcParams->StandardInput;
     SiEx.StartupInfo.hStdOutput = pParentProcParams->StandardOutput;
@@ -3659,7 +3957,7 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
     /*
      * Construct the command line and launch the process.
      */
-    PRTUTF16 pwszCmdLine = supR3HardenedWinConstructCmdLine(NULL, iWhich);
+    PRTUTF16 pwszCmdLine = supR3HardNtChildConstructCmdLine(NULL, iWhich);
 
     supR3HardenedWinEnableThreadCreation();
     PROCESS_INFORMATION ProcessInfoW32;
@@ -3676,13 +3974,13 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
         supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
                               "Error relaunching VirtualBox VM process: %u\n"
                               "Command line: '%ls'",
-                              GetLastError(), pwszCmdLine);
+                              RtlGetLastWin32Error(), pwszCmdLine);
     supR3HardenedWinDisableThreadCreation();
 
     SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): New child %x.%x [kernel32].\n",
                  iWhich, ProcessInfoW32.dwProcessId, ProcessInfoW32.dwThreadId));
-    HANDLE hProcess = ProcessInfoW32.hProcess;
-    HANDLE hThread  = ProcessInfoW32.hThread;
+    This.hProcess = ProcessInfoW32.hProcess;
+    This.hThread  = ProcessInfoW32.hThread;
 
 #else
 
@@ -3695,7 +3993,7 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
     W32ImageName.MaximumLength = W32ImageName.Length + sizeof(WCHAR);
 
     UNICODE_STRING CmdLine;
-    supR3HardenedWinConstructCmdLine(&CmdLine, iWhich);
+    supR3HardNtChildConstructCmdLine(&CmdLine, iWhich);
 
     PRTL_USER_PROCESS_PARAMETERS pProcParams = NULL;
     SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateProcessParameters(&pProcParams,
@@ -3738,178 +4036,239 @@ static int supR3HardenedWinDoReSpawn(int iWhich)
                  iWhich, ProcessInfo.ClientId.UniqueProcess, ProcessInfo.ClientId.UniqueThread));
     RtlDestroyProcessParameters(pProcParams);
 
-    HANDLE hProcess = ProcessInfoNt.ProcessHandle;
-    HANDLE hThread  = ProcessInfoNt.ThreadHandle;
+    This.hProcess = ProcessInfoNt.ProcessHandle;
+    This.hThread  = ProcessInfoNt.ThreadHandle;
 #endif
 
 #ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
     /*
      * Apply anti debugger notification trick to the thread.  (Also done in
-     * supR3HardenedWinInstallHooks.)
+     * supR3HardenedWinInit.)  This may fail with STATUS_ACCESS_DENIED and
+     * maybe other errors.
      */
-    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
+    rcNt = NtSetInformationThread(This.hThread, ThreadHideFromDebugger, NULL, 0);
     if (!NT_SUCCESS(rcNt))
-    {
-        NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
-        supR3HardenedError(rcNt, true /*fFatal*/, "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
-    }
+        SUP_DPRINTF(("supR3HardenedWinReSpawn: NtSetInformationThread/ThreadHideFromDebugger failed: %#x (harmless)\n", rcNt));
 #endif
 
     /*
-     * Clean up the process.
+     * Perform very early child initialization.
      */
-    int rc = supR3HardenedWinPurifyChild(hProcess, hThread, RTErrInfoInitStatic(&g_ErrInfoStatic));
-    if (RT_FAILURE(rc))
-    {
-        NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
-        supR3HardenedError(rc, true /*fFatal*/, "%s", g_ErrInfoStatic.szMsg);
-    }
+    supR3HardNtChildGatherData(&This);
+    supR3HardNtChildScrewUpPebForInitialImageEvents(&This);
+    supR3HardNtChildSetUpChildInit(&This);
+
+    ULONG cSuspendCount = 0;
+    rcNt = NtResumeThread(This.hThread, &cSuspendCount);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedWinKillChild(&This, "supR3HardenedWinDoReSpawn", rcNt, "NtResumeThread failed: %#x", rcNt);
 
     /*
-     * Start the process execution.
+     * Santizie the pre-NTDLL child when it's ready.
+     *
+     * AV software and other things injecting themselves into the embryonic
+     * and budding process to intercept API calls and what not.  Unfortunately
+     * this is also the behavior of viruses, malware and other unfriendly
+     * software, so we won't stand for it.  AV software can scan our image
+     * as they are loaded via kernel hooks, that's sufficient.  No need for
+     * patching half of NTDLL or messing with the import table of the
+     * process executable.
      */
-    ULONG cSuspendCount = 0;
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtResumeThread(hThread, &cSuspendCount));
+    supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_PurifyChildAndCloseHandles, 2000 /*ms*/, "PurifyChildAndCloseHandles");
+    supR3HardNtChildPurify(&This);
+    supR3HardNtChildSanitizePeb(&This);
 
     /*
      * Close the unrestricted access handles.  Since we need to wait on the
      * child process, we'll reopen the process with limited access before doing
      * away with the process handle returned by CreateProcess.
      */
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hThread));
+    supR3HardNtChildCloseFullAccessHandles(&This);
 
-    PROCESS_BASIC_INFORMATION BasicInfo;
-    HANDLE hProcWait;
-    ULONG fRights = SYNCHRONIZE;
-    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)) /* Introduced in Vista. */
-        fRights |= PROCESS_QUERY_LIMITED_INFORMATION;
-    else
-        fRights |= PROCESS_QUERY_INFORMATION;
-    rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
-                             NtCurrentProcess(), &hProcWait,
-                             fRights, 0 /*HandleAttributes*/, 0);
-    if (rcNt == STATUS_ACCESS_DENIED)
-        rcNt = NtDuplicateObject(NtCurrentProcess(), hProcess,
-                                 NtCurrentProcess(), &hProcWait,
-                                 SYNCHRONIZE, 0 /*HandleAttributes*/, 0);
+    /*
+     * Signal the child that we've closed the unrestricted handles and it can
+     * safely try open the driver.
+     */
+    rcNt = NtSetEvent(This.hEvtChild, NULL);
     if (!NT_SUCCESS(rcNt))
-    {
-        /* Failure is unacceptable, kill the process. */
-        NtTerminateProcess(hProcess, RTEXITCODE_FAILURE);
-        supR3HardenedError(rcNt, false /*fFatal*/, "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
-
-        NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
-        bool fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
-        if (!fExitOk)
-        {
-            NTSTATUS rcNtWait;
-            DWORD dwStartTick = GetTickCount();
-            do
-            {
-                NtTerminateProcess(hProcess, DBG_TERMINATE_PROCESS);
-
-                LARGE_INTEGER Timeout;
-                Timeout.QuadPart = -20000000; /* 2 second */
-                rcNtWait = NtWaitForSingleObject(hProcess, TRUE /*Alertable*/, &Timeout);
-
-                rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
-                fExitOk = NT_SUCCESS(rcNtExit) && BasicInfo.ExitStatus != STATUS_PENDING;
-            } while (   !fExitOk
-                     && (   rcNtWait == STATUS_TIMEOUT
-                         || rcNtWait == STATUS_USER_APC
-                         || rcNtWait == STATUS_ALERTED)
-                     && GetTickCount() - dwStartTick < 60 * 1000);
-            if (fExitOk)
-                supR3HardenedError(rcNt, false /*fFatal*/,
-                                   "NtDuplicateObject failed and we failed to kill child: rcNt=%u rcNtWait=%u hProcess=%p\n",
-                                   rcNt, rcNtWait, hProcess);
-        }
-        supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, VERR_INVALID_NAME,
-                              "NtDuplicateObject failed on child process handle: %#x\n", rcNt);
-    }
-
-    SUPR3HARDENED_ASSERT_NT_SUCCESS(NtClose(hProcess));
-    hProcess = NULL;
+        supR3HardenedWinKillChild(&This, "supR3HardenedWinReSpawn", VERR_INVALID_NAME,
+                                  "NtSetEvent failed on child process handle: %#x\n", rcNt);
 
     /*
      * Ditch the loader cache so we don't sit on too much memory while waiting.
      */
     supR3HardenedWinFlushLoaderCache();
-    HeapCompact(GetProcessHeap(), 0 /*dwFlags*/);
+    supR3HardenedWinCompactHeaps();
 
     /*
-     * If this is the middle process, wait for both parent and child to quit.
+     * Enable thread creation at this point so Ctrl-C and Ctrl-Break can be processed.
      */
-    HANDLE hParent = NULL;
-    if (iWhich > 1)
-    {
-        rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
-        if (NT_SUCCESS(rcNt))
-        {
-            OBJECT_ATTRIBUTES ObjAttr;
-            InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    supR3HardenedWinEnableThreadCreation();
 
-            CLIENT_ID ClientId;
-            ClientId.UniqueProcess = (HANDLE)BasicInfo.InheritedFromUniqueProcessId;
-            ClientId.UniqueThread  = NULL;
+    /*
+     * Wait for the child to get to suplibHardenedWindowsMain so we can close the handles.
+     */
+    supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_CloseEvents, 60000 /*ms*/, "CloseEvents");
 
-            rcNt = NtOpenProcess(&hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
-        }
-#ifdef DEBUG
-        SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
-#endif
+    NtClose(This.hEvtChild);
+    NtClose(This.hEvtParent);
+    This.hEvtChild  = NULL;
+    This.hEvtParent = NULL;
+
+    /*
+     * Wait for the process to terminate.
+     */
+    supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_End, RT_INDEFINITE_WAIT, "the end");
+    SUPR3HARDENED_ASSERT(false); /* We're not supposed to get here! */
+}
+
+
+/**
+ * Logs the content of the given object directory.
+ *
+ * @returns true if it exists, false if not.
+ * @param   pszDir             The path of the directory to log (ASCII).
+ */
+static void supR3HardenedWinLogObjDir(const char *pszDir)
+{
+    /*
+     * Open the driver object directory.
+     */
+    RTUTF16 wszDir[128];
+    int rc = RTUtf16CopyAscii(wszDir, RT_ELEMENTS(wszDir), pszDir);
+    if (RT_FAILURE(rc))
+    {
+        SUP_DPRINTF(("supR3HardenedWinLogObjDir: RTUtf16CopyAscii -> %Rrc on '%s'\n", rc, pszDir));
+        return;
     }
 
-    if (hParent != NULL)
+    UNICODE_STRING NtDirName;
+    NtDirName.Buffer = (WCHAR *)wszDir;
+    NtDirName.Length = (USHORT)(RTUtf16Len(wszDir) * sizeof(WCHAR));
+    NtDirName.MaximumLength = NtDirName.Length + sizeof(WCHAR);
+
+    OBJECT_ATTRIBUTES ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+    HANDLE hDir;
+    NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
+    SUP_DPRINTF(("supR3HardenedWinLogObjDir: %ls => %#x\n", wszDir, rcNt));
+    if (!NT_SUCCESS(rcNt))
+        return;
+
+    /*
+     * Enumerate it, looking for the driver.
+     */
+    ULONG uObjDirCtx = 0;
+    for (;;)
     {
-        for (;;)
+        uint32_t    abBuffer[_64K + _1K];
+        ULONG       cbActual;
+        rcNt = NtQueryDirectoryObject(hDir,
+                                      abBuffer,
+                                      sizeof(abBuffer) - 4, /* minus four for string terminator space. */
+                                      FALSE /*ReturnSingleEntry */,
+                                      FALSE /*RestartScan*/,
+                                      &uObjDirCtx,
+                                      &cbActual);
+        if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
         {
-            HANDLE ahHandles[2] = { hProcWait, hParent };
-            rcNt = NtWaitForMultipleObjects(2, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*pTimeout*/);
-            if (   rcNt == STATUS_WAIT_0
-                || rcNt == STATUS_WAIT_0 + 1
-                || rcNt == STATUS_ABANDONED_WAIT_0
-                || rcNt == STATUS_ABANDONED_WAIT_0 + 1)
-                break;
-            if (   rcNt != STATUS_TIMEOUT
-                && rcNt != STATUS_USER_APC
-                && rcNt != STATUS_ALERTED)
-                supR3HardenedFatal("NtWaitForMultipleObjects returned %#x\n", rcNt);
+            SUP_DPRINTF(("supR3HardenedWinLogObjDir: NtQueryDirectoryObject => rcNt=%#x cbActual=%#x\n", rcNt, cbActual));
+            break;
+        }
+
+        POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
+        while (pObjDir->Name.Length != 0)
+        {
+            WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
+            SUP_DPRINTF(("  %.*ls  %.*ls\n",
+                         pObjDir->TypeName.Length / sizeof(WCHAR), pObjDir->TypeName.Buffer,
+                         pObjDir->Name.Length / sizeof(WCHAR), pObjDir->Name.Buffer));
+
+            /* Next directory entry. */
+            pObjDir++;
         }
-        NtClose(hParent);
     }
-    else
+
+    /*
+     * Clean up and return.
+     */
+    NtClose(hDir);
+}
+
+
+/**
+ * Tries to open VBoxDrvErrorInfo and read extra error info from it.
+ *
+ * @returns pszErrorInfo.
+ * @param   pszErrorInfo        The destination buffer.  Will always be
+ *                              terminated.
+ * @param   cbErrorInfo         The size of the destination buffer.
+ * @param   pszPrefix           What to prefix the error info with, if we got
+ *                              anything.
+ */
+DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix)
+{
+    RT_BZERO(pszErrorInfo, cbErrorInfo);
+
+    /*
+     * Try open the device.
+     */
+    HANDLE              hFile  = RTNT_INVALID_HANDLE_VALUE;
+    IO_STATUS_BLOCK     Ios    = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+    UNICODE_STRING      NtName = RTNT_CONSTANT_UNISTR(SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+    OBJECT_ATTRIBUTES   ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    NTSTATUS rcNt = NtCreateFile(&hFile,
+                                 GENERIC_READ, /* No SYNCHRONIZE. */
+                                 &ObjAttr,
+                                 &Ios,
+                                 NULL /* Allocation Size*/,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 FILE_OPEN,
+                                 FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT. */
+                                 NULL /*EaBuffer*/,
+                                 0 /*EaLength*/);
+    if (NT_SUCCESS(rcNt))
+        rcNt = Ios.Status;
+    if (NT_SUCCESS(rcNt))
     {
         /*
-         * Wait for the process to terminate.
+         * Try read error info.
          */
-        for (;;)
+        size_t cchPrefix = strlen(pszPrefix);
+        if (cchPrefix + 3 < cbErrorInfo)
         {
-            rcNt = NtWaitForSingleObject(hProcWait, TRUE /*Alertable*/, NULL /*pTimeout*/);
-            if (   rcNt == STATUS_WAIT_0
-                || rcNt == STATUS_ABANDONED_WAIT_0)
-                break;
-            if (   rcNt != STATUS_TIMEOUT
-                && rcNt != STATUS_USER_APC
-                && rcNt != STATUS_ALERTED)
-                supR3HardenedFatal("NtWaitForSingleObject returned %#x\n", rcNt);
+            LARGE_INTEGER offRead;
+            offRead.QuadPart = 0;
+            rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+                              &pszErrorInfo[cchPrefix], (ULONG)(cbErrorInfo - cchPrefix - 1), &offRead, NULL);
+            if (NT_SUCCESS(rcNt))
+            {
+                memcpy(pszErrorInfo, pszPrefix, cchPrefix);
+                pszErrorInfo[cbErrorInfo - 1] = '\0';
+                SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: '%s'", &pszErrorInfo[cchPrefix]));
+            }
+            else
+            {
+                *pszErrorInfo = '\0';
+                if (rcNt != STATUS_END_OF_FILE)
+                    SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtReadFile -> %#x\n", rcNt));
+            }
         }
+        else
+            RTStrCopy(pszErrorInfo, cbErrorInfo, "error info buffer too small");
+        NtClose(hFile);
     }
+    else
+        SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtCreateFile -> %#x\n", rcNt));
 
-    /*
-     * Proxy the termination code of the child, if it exited already.
-     */
-    NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
-    if (   !NT_SUCCESS(rcNt2)
-        || BasicInfo.ExitStatus == STATUS_PENDING)
-        BasicInfo.ExitStatus = RTEXITCODE_FAILURE;
-
-    NtClose(hProcWait);
-    SUP_DPRINTF(("supR3HardenedWinDoReSpawn(%d): Quitting: ExitCode=%#x rcNt=%#x\n", iWhich, BasicInfo.ExitStatus, rcNt));
-    suplibHardenedExit((RTEXITCODE)BasicInfo.ExitStatus);
+    return pszErrorInfo;
 }
 
 
+
 /**
  * Checks if the driver exists.
  *
@@ -3989,11 +4348,14 @@ static bool supR3HardenedWinDriverExists(const char *pszDriver)
  */
 static void supR3HardenedWinOpenStubDevice(void)
 {
+    if (g_fSupStubOpened)
+        return;
+
     /*
      * Retry if we think driver might still be initializing (STATUS_NO_SUCH_DEVICE + \Drivers\VBoxDrv).
      */
-    static const WCHAR  s_wszName[] = L"\\Device\\VBoxDrvStub";
-    DWORD const         uStartTick = GetTickCount();
+    static const WCHAR  s_wszName[] = SUPDRV_NT_DEVICE_NAME_STUB;
+    uint64_t const      uMsTsStart = supR3HardenedWinGetMilliTS();
     NTSTATUS            rcNt;
     uint32_t            iTry;
 
@@ -4011,14 +4373,14 @@ static void supR3HardenedWinOpenStubDevice(void)
         InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
 
         rcNt = NtCreateFile(&hFile,
-                            GENERIC_READ | GENERIC_WRITE,
+                            GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
                             &ObjAttr,
                             &Ios,
                             NULL /* Allocation Size*/,
                             FILE_ATTRIBUTE_NORMAL,
                             FILE_SHARE_READ | FILE_SHARE_WRITE,
                             FILE_OPEN,
-                            FILE_NON_DIRECTORY_FILE,
+                            FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT. */
                             NULL /*EaBuffer*/,
                             0 /*EaLength*/);
         if (NT_SUCCESS(rcNt))
@@ -4028,7 +4390,7 @@ static void supR3HardenedWinOpenStubDevice(void)
            completely initialized.  Delay a little bit and try again. */
         if (rcNt != STATUS_NO_SUCH_DEVICE)
             break;
-        if (iTry > 0 && GetTickCount() - uStartTick > 5000)  /* 5 sec, at least two tries */
+        if (iTry > 0 && supR3HardenedWinGetMilliTS() - uMsTsStart > 5000)  /* 5 sec, at least two tries */
             break;
         if (!supR3HardenedWinDriverExists("VBoxDrv"))
         {
@@ -4047,11 +4409,63 @@ static void supR3HardenedWinOpenStubDevice(void)
         NtDelayExecution(TRUE, &Time);
     }
 
-    if (!NT_SUCCESS(rcNt))
+    if (NT_SUCCESS(rcNt))
+        g_fSupStubOpened = true;
+    else
     {
+        /*
+         * Report trouble (fatal).  For some errors codes we try gather some
+         * extra information that goes into VBoxStartup.log so that we stand a
+         * better chance resolving the issue.
+         */
+        char szErrorInfo[_4K];
         int rc = VERR_OPEN_FAILED;
         if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
+        {
             rc = SUP_NT_STATUS_TO_VBOX(rcNt);
+
+            /*
+             * \Windows\ApiPort open trouble.  So far only
+             * STATUS_OBJECT_TYPE_MISMATCH has been observed.
+             */
+            if (rc == VERR_SUPDRV_APIPORT_OPEN_ERROR)
+            {
+                SUP_DPRINTF(("Error opening VBoxDrvStub: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"));
+
+                uint32_t uSessionId = NtCurrentPeb()->SessionId;
+                SUP_DPRINTF(("  SessionID=%#x\n", uSessionId));
+                char szDir[64];
+                if (uSessionId == 0)
+                    RTStrCopy(szDir, sizeof(szDir), "\\Windows");
+                else
+                {
+                    RTStrPrintf(szDir, sizeof(szDir), "\\Sessions\\%u\\Windows", uSessionId);
+                    supR3HardenedWinLogObjDir(szDir);
+                }
+                supR3HardenedWinLogObjDir("\\Windows");
+                supR3HardenedWinLogObjDir("\\Sessions");
+
+                supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, rc,
+                                      "NtCreateFile(%ls) failed: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"
+                                      "\n"
+                                      "Error getting %s\\ApiPort in the driver from vboxdrv.\n"
+                                      "\n"
+                                      "Could be due to security software is redirecting access to it, so please include full "
+                                      "details of such software in a bug report. VBoxStartup.log may contain details important "
+                                      "to resolving the issue.%s"
+                                      , s_wszName, szDir,
+                                      supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                          "\n\nVBoxDrvStub error: "));
+            }
+
+            /*
+             * Generic VBox failure message.
+             */
+            supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
+                                  "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)%s", s_wszName, rc, rcNt,
+                                  supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                    "\nVBoxDrvStub error: "));
+        }
         else
         {
             const char *pszDefine;
@@ -4063,11 +4477,44 @@ static void supR3HardenedWinOpenStubDevice(void)
                 case STATUS_TRUST_FAILURE:          pszDefine = " STATUS_TRUST_FAILURE"; break;
                 default:                            pszDefine = ""; break;
             }
+
+            /*
+             * Problems opening the device is generally due to driver load/
+             * unload issues.  Check whether the driver is loaded and make
+             * suggestions accordingly.
+             */
+/** @todo don't fail during early init, wait till later and try load the driver if missing or at least query the service manager for additional information. */
+            if (   rcNt == STATUS_NO_SUCH_DEVICE
+                || rcNt == STATUS_OBJECT_NAME_NOT_FOUND)
+            {
+                SUP_DPRINTF(("Error opening VBoxDrvStub: %s\n", pszDefine));
+                if (supR3HardenedWinDriverExists("VBoxDrv"))
+                    supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
+                                          "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
+                                          "\n"
+                                          "Driver is probably stuck stopping/starting. Try 'sc.exe query vboxdrv' to get more "
+                                          "information about its state. Rebooting may actually help.%s"
+                                          , s_wszName, rcNt, pszDefine, iTry,
+                                          supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                              "\nVBoxDrvStub error: "));
+                else
+                    supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
+                                          "NtCreateFile(%ls) failed: %#x%s (%u retries)\n"
+                                          "\n"
+                                          "Driver is does not appear to be loaded. Try 'sc.exe start vboxdrv', reinstall "
+                                          "VirtualBox or reboot.%s"
+                                          , s_wszName, rcNt, pszDefine, iTry,
+                                          supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                              "\nVBoxDrvStub error: "));
+            }
+
+            /* Generic NT failure message. */
             supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
-                                  "NtCreateFile(%ls) failed: %#x%s (%u retries)\n", s_wszName, rcNt, pszDefine, iTry);
+                                  "NtCreateFile(%ls) failed: %#x%s (%u retries)%s",
+                                  s_wszName, rcNt, pszDefine, iTry,
+                                  supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                      "\nVBoxDrvStub error: "));
         }
-        supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
-                              "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)\n", s_wszName, rc, rcNt);
     }
 }
 
@@ -4081,15 +4528,34 @@ DECLHIDDEN(int) supR3HardenedWinReSpawn(int iWhich)
 {
     /*
      * Before the 2nd respawn we set up a child protection deal with the
-     * support driver via /Devices/VBoxDrvStub.
+     * support driver via /Devices/VBoxDrvStub.  (We tried to do this
+     * during the early init, but in case we had trouble accessing vboxdrv we
+     * retry it here where we have kernel32.dll and others to pull in for
+     * better diagnostics.)
      */
     if (iWhich == 2)
         supR3HardenedWinOpenStubDevice();
 
     /*
+     * Make sure we're alone in the stub process before creating the VM process
+     * and that there isn't any debuggers attached.
+     */
+    if (iWhich == 2)
+    {
+        int rc = supHardNtVpDebugger(NtCurrentProcess(), RTErrInfoInitStatic(&g_ErrInfoStatic));
+        if (RT_SUCCESS(rc))
+            rc = supHardNtVpThread(NtCurrentProcess(), NtCurrentThread(), RTErrInfoInitStatic(&g_ErrInfoStatic));
+        if (RT_FAILURE(rc))
+            supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Integrity, rc, "%s", g_ErrInfoStatic.szMsg);
+    }
+
+
+    /*
      * Respawn the process with kernel protection for the new process.
      */
-    return supR3HardenedWinDoReSpawn(iWhich);
+    supR3HardenedWinDoReSpawn(iWhich);
+    SUPR3HARDENED_ASSERT(false); /* We're not supposed to get here! */
+    return RTEXITCODE_FAILURE;
 }
 
 
@@ -4130,57 +4596,116 @@ DECLHIDDEN(bool) supR3HardenedWinIsReSpawnNeeded(int iWhich, int cArgs, char **p
 }
 
 
-/**
- * Initializes the windows verficiation bits.
- * @param   fFlags          The main flags.
- */
-DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags)
-{
+/**
+ * Initializes the windows verficiation bits and other things we're better off
+ * doing after main() has passed on it's data.
+ *
+ * @param   fFlags          The main flags.
+ * @param   fAvastKludge    Whether to apply the avast kludge.
+ */
+DECLHIDDEN(void) supR3HardenedWinInit(uint32_t fFlags, bool fAvastKludge)
+{
+    NTSTATUS rcNt;
+
+#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
+    /*
+     * Install a anti debugging hack before we continue.  This prevents most
+     * notifications from ending up in the debugger. (Also applied to the
+     * child process when respawning.)
+     */
+    rcNt = NtSetInformationThread(NtCurrentThread(), ThreadHideFromDebugger, NULL, 0);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
+                              "NtSetInformationThread/ThreadHideFromDebugger failed: %#x\n", rcNt);
+#endif
+
+    /*
+     * Init the verifier.
+     */
     RTErrInfoInitStatic(&g_ErrInfoStatic);
     int rc = supHardenedWinInitImageVerifier(&g_ErrInfoStatic.Core);
     if (RT_FAILURE(rc))
         supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rc,
                               "supHardenedWinInitImageVerifier failed: %s", g_ErrInfoStatic.szMsg);
 
+    /*
+     * Get the windows system directory from the KnownDlls dir.
+     */
+    HANDLE              hSymlink = INVALID_HANDLE_VALUE;
+    UNICODE_STRING      UniStr = RTNT_CONSTANT_UNISTR(L"\\KnownDlls\\KnownDllPath");
+    OBJECT_ATTRIBUTES   ObjAttrs;
+    InitializeObjectAttributes(&ObjAttrs, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    rcNt = NtOpenSymbolicLinkObject(&hSymlink, SYMBOLIC_LINK_QUERY, &ObjAttrs);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error opening '%ls': %#x", UniStr.Buffer, rcNt);
+
+    g_System32WinPath.UniStr.Buffer = g_System32WinPath.awcBuffer;
+    g_System32WinPath.UniStr.Length = 0;
+    g_System32WinPath.UniStr.MaximumLength = sizeof(g_System32WinPath.awcBuffer) - sizeof(RTUTF16);
+    rcNt = NtQuerySymbolicLinkObject(hSymlink, &g_System32WinPath.UniStr, NULL);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error querying '%ls': %#x", UniStr.Buffer, rcNt);
+    g_System32WinPath.UniStr.Buffer[g_System32WinPath.UniStr.Length / sizeof(RTUTF16)] = '\0';
+
+    SUP_DPRINTF(("KnownDllPath: %ls\n", g_System32WinPath.UniStr.Buffer));
+    NtClose(hSymlink);
+
     if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
     {
-        /*
-         * Do a self purification to cure avast's weird NtOpenFile write-thru
-         * change in GetBinaryTypeW change in kernel32.  Unfortunately, avast
-         * uses a system thread to perform the process modifications, which
-         * means it's hard to make sure it had the chance to make them...
-         *
-         * We have to resort to kludge doing yield and sleep fudging for a
-         * number of milliseconds and schedulings before we can hope that avast
-         * and similar products have done what they need to do.  If we do any
-         * fixes, we wait for a while again and redo it until we're clean.
-         *
-         * This is unfortunately kind of fragile.
-         */
-        uint32_t iLoop = 0;
-        uint32_t cFixes;
-        do
+        if (fAvastKludge)
         {
-            uint32_t    cSleeps = 0;
-            DWORD       dwStart = GetTickCount();
-            do
+            /*
+             * Do a self purification to cure avast's weird NtOpenFile write-thru
+             * change in GetBinaryTypeW change in kernel32.  Unfortunately, avast
+             * uses a system thread to perform the process modifications, which
+             * means it's hard to make sure it had the chance to make them...
+             *
+             * We have to resort to kludge doing yield and sleep fudging for a
+             * number of milliseconds and schedulings before we can hope that avast
+             * and similar products have done what they need to do.  If we do any
+             * fixes, we wait for a while again and redo it until we're clean.
+             *
+             * This is unfortunately kind of fragile.
+             */
+            uint32_t cMsFudge = g_fSupAdversaries ? 512 : 128;
+            uint32_t cFixes;
+            for (uint32_t iLoop = 0; iLoop < 16; iLoop++)
             {
-                NtYieldExecution();
-                LARGE_INTEGER Time;
-                Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
-                NtDelayExecution(FALSE, &Time);
-                cSleeps++;
-            } while (   GetTickCount() - dwStart <= 80
-                     || cSleeps < 8);
-            SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
-                         iLoop, GetTickCount() - dwStart, cSleeps));
-
-            cFixes = 0;
-            rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
-                                             &cFixes, NULL /*pErrInfo*/);
-        } while (   RT_SUCCESS(rc)
-                 && cFixes > 0
-                 && ++iLoop < 8);
+                uint32_t cSleeps = 0;
+                uint64_t uMsTsStart = supR3HardenedWinGetMilliTS();
+                do
+                {
+                    NtYieldExecution();
+                    LARGE_INTEGER Time;
+                    Time.QuadPart = -8000000 / 100; /* 8ms in 100ns units, relative time. */
+                    NtDelayExecution(FALSE, &Time);
+                    cSleeps++;
+                } while (   supR3HardenedWinGetMilliTS() - uMsTsStart <= cMsFudge
+                         || cSleeps < 8);
+                SUP_DPRINTF(("supR3HardenedWinInit: Startup delay kludge #2/%u: %u ms, %u sleeps\n",
+                             iLoop, supR3HardenedWinGetMilliTS() - uMsTsStart, cSleeps));
+
+                cFixes = 0;
+                rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
+                                                 0 /*fFlags*/, &cFixes, NULL /*pErrInfo*/);
+                if (RT_FAILURE(rc) || cFixes == 0)
+                    break;
+
+                if (!g_fSupAdversaries)
+                    g_fSupAdversaries |= SUPHARDNT_ADVERSARY_UNKNOWN;
+                cMsFudge = 512;
+
+                /* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
+                ULONG cPatchCount = 0;
+                rcNt = NtQuerySystemInformation(SystemInformation_KiOpPrefetchPatchCount,
+                                                &cPatchCount, sizeof(cPatchCount), NULL);
+                if (NT_SUCCESS(rcNt))
+                    SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x cPatchCount=%#u\n",
+                                 cFixes, g_fSupAdversaries, cPatchCount));
+                else
+                    SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
+            }
+        }
 
         /*
          * Install the hooks.
@@ -4223,7 +4748,7 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
      */
     int    cArgs          = 0;
     int    cArgsAllocated = 4;
-    char **papszArgs      = (char **)suplibHardenedAllocZ(sizeof(char *) * cArgsAllocated);
+    char **papszArgs      = (char **)RTMemAllocZ(sizeof(char *) * cArgsAllocated);
     char  *pszSrc         = pszCmdLine;
     for (;;)
     {
@@ -4238,7 +4763,7 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
         if (cArgs + 2 >= cArgsAllocated)
         {
             cArgsAllocated *= 2;
-            papszArgs = (char **)suplibHardenedReAlloc(papszArgs, sizeof(char *) * cArgsAllocated);
+            papszArgs = (char **)RTMemRealloc(papszArgs, sizeof(char *) * cArgsAllocated);
         }
         papszArgs[cArgs++] = pszSrc;
         papszArgs[cArgs]   = NULL;
@@ -4291,6 +4816,516 @@ static char **suplibCommandLineToArgvWStub(PCRTUTF16 pawcCmdLine, size_t cwcCmdL
 }
 
 
+/**
+ * Logs information about a file from a protection product or from Windows.
+ *
+ * The purpose here is to better see which version of the product is installed
+ * and not needing to depend on the user supplying the correct information.
+ *
+ * @param   pwszFile            The NT path to the file.
+ * @param   fAdversarial        Set if from a protection product, false if
+ *                              system file.
+ */
+static void supR3HardenedLogFileInfo(PCRTUTF16 pwszFile, bool fAdversarial)
+{
+    /*
+     * Open the file.
+     */
+    HANDLE              hFile  = RTNT_INVALID_HANDLE_VALUE;
+    IO_STATUS_BLOCK     Ios    = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+    UNICODE_STRING      UniStrName;
+    UniStrName.Buffer = (WCHAR *)pwszFile;
+    UniStrName.Length = (USHORT)(RTUtf16Len(pwszFile) * sizeof(WCHAR));
+    UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
+    OBJECT_ATTRIBUTES   ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    NTSTATUS rcNt = NtCreateFile(&hFile,
+                                 GENERIC_READ | SYNCHRONIZE,
+                                 &ObjAttr,
+                                 &Ios,
+                                 NULL /* Allocation Size*/,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 FILE_SHARE_READ,
+                                 FILE_OPEN,
+                                 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                                 NULL /*EaBuffer*/,
+                                 0 /*EaLength*/);
+    if (NT_SUCCESS(rcNt))
+        rcNt = Ios.Status;
+    if (NT_SUCCESS(rcNt))
+    {
+        SUP_DPRINTF(("%ls:\n", pwszFile));
+        union
+        {
+            uint64_t                    u64AlignmentInsurance;
+            FILE_BASIC_INFORMATION      BasicInfo;
+            FILE_STANDARD_INFORMATION   StdInfo;
+            uint8_t                     abBuf[32768];
+            RTUTF16                     awcBuf[16384];
+            IMAGE_DOS_HEADER            MzHdr;
+        } u;
+        RTTIMESPEC  TimeSpec;
+        char        szTmp[64];
+
+        /*
+         * Print basic file information available via NtQueryInformationFile.
+         */
+        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+        rcNt = NtQueryInformationFile(hFile, &Ios, &u.BasicInfo, sizeof(u.BasicInfo), FileBasicInformation);
+        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+        {
+            SUP_DPRINTF(("    CreationTime:    %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.CreationTime.QuadPart), szTmp, sizeof(szTmp))));
+            /*SUP_DPRINTF(("    LastAccessTime:  %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastAccessTime.QuadPart), szTmp, sizeof(szTmp))));*/
+            SUP_DPRINTF(("    LastWriteTime:   %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastWriteTime.QuadPart), szTmp, sizeof(szTmp))));
+            SUP_DPRINTF(("    ChangeTime:      %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.ChangeTime.QuadPart), szTmp, sizeof(szTmp))));
+            SUP_DPRINTF(("    FileAttributes:  %#x\n", u.BasicInfo.FileAttributes));
+        }
+        else
+            SUP_DPRINTF(("    FileBasicInformation -> %#x %#x\n", rcNt, Ios.Status));
+
+        rcNt = NtQueryInformationFile(hFile, &Ios, &u.StdInfo, sizeof(u.StdInfo), FileStandardInformation);
+        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+            SUP_DPRINTF(("    Size:            %#llx\n", u.StdInfo.EndOfFile.QuadPart));
+        else
+            SUP_DPRINTF(("    FileStandardInformation -> %#x %#x\n", rcNt, Ios.Status));
+
+        /*
+         * Read the image header and extract the timestamp and other useful info.
+         */
+        RT_ZERO(u);
+        LARGE_INTEGER offRead;
+        offRead.QuadPart = 0;
+        rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+                          &u, (ULONG)sizeof(u), &offRead, NULL);
+        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+        {
+            uint32_t offNtHdrs = 0;
+            if (u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE)
+                offNtHdrs = u.MzHdr.e_lfanew;
+            if (offNtHdrs < sizeof(u) - sizeof(IMAGE_NT_HEADERS))
+            {
+                PIMAGE_NT_HEADERS64 pNtHdrs64 = (PIMAGE_NT_HEADERS64)&u.abBuf[offNtHdrs];
+                PIMAGE_NT_HEADERS32 pNtHdrs32 = (PIMAGE_NT_HEADERS32)&u.abBuf[offNtHdrs];
+                if (pNtHdrs64->Signature == IMAGE_NT_SIGNATURE)
+                {
+                    SUP_DPRINTF(("    NT Headers:      %#x\n", offNtHdrs));
+                    SUP_DPRINTF(("    Timestamp:       %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
+                    SUP_DPRINTF(("    Machine:         %#x%s\n", pNtHdrs64->FileHeader.Machine,
+                                 pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 ? " - i386"
+                                 : pNtHdrs64->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ? " - amd64" : ""));
+                    SUP_DPRINTF(("    Timestamp:       %#x\n", pNtHdrs64->FileHeader.TimeDateStamp));
+                    SUP_DPRINTF(("    Image Version:   %u.%u\n",
+                                 pNtHdrs64->OptionalHeader.MajorImageVersion, pNtHdrs64->OptionalHeader.MinorImageVersion));
+                    SUP_DPRINTF(("    SizeOfImage:     %#x (%u)\n", pNtHdrs64->OptionalHeader.SizeOfImage, pNtHdrs64->OptionalHeader.SizeOfImage));
+
+                    /*
+                     * Very crude way to extract info from the file version resource.
+                     */
+                    PIMAGE_SECTION_HEADER paSectHdrs = (PIMAGE_SECTION_HEADER)(  (uintptr_t)&pNtHdrs64->OptionalHeader
+                                                                               + pNtHdrs64->FileHeader.SizeOfOptionalHeader);
+                    IMAGE_DATA_DIRECTORY  RsrcDir = { 0, 0 };
+                    if (   pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)
+                        && pNtHdrs64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
+                        RsrcDir = pNtHdrs64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
+                    else if (   pNtHdrs64->FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
+                             && pNtHdrs32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE)
+                        RsrcDir = pNtHdrs32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
+                    SUP_DPRINTF(("    Resource Dir:    %#x LB %#x\n", RsrcDir.VirtualAddress, RsrcDir.Size));
+                    if (   RsrcDir.VirtualAddress > offNtHdrs
+                        && RsrcDir.Size > 0
+                        &&    (uintptr_t)&u + sizeof(u) - (uintptr_t)paSectHdrs
+                           >= pNtHdrs64->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) )
+                    {
+                        offRead.QuadPart = 0;
+                        for (uint32_t i = 0; i < pNtHdrs64->FileHeader.NumberOfSections; i++)
+                            if (   paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress < paSectHdrs[i].SizeOfRawData
+                                && paSectHdrs[i].PointerToRawData > offNtHdrs)
+                            {
+                                offRead.QuadPart = paSectHdrs[i].PointerToRawData
+                                                 + (paSectHdrs[i].VirtualAddress - RsrcDir.VirtualAddress);
+                                break;
+                            }
+                        if (offRead.QuadPart > 0)
+                        {
+                            RT_ZERO(u);
+                            rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+                                              &u, (ULONG)sizeof(u), &offRead, NULL);
+                            if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+                            {
+                                static const struct { PCRTUTF16 pwsz; size_t cb; } s_abFields[] =
+                                {
+#define MY_WIDE_STR_TUPLE(a_sz)     { L ## a_sz, sizeof(L ## a_sz) - sizeof(RTUTF16) }
+                                    MY_WIDE_STR_TUPLE("ProductName"),
+                                    MY_WIDE_STR_TUPLE("ProductVersion"),
+                                    MY_WIDE_STR_TUPLE("FileVersion"),
+                                    MY_WIDE_STR_TUPLE("SpecialBuild"),
+                                    MY_WIDE_STR_TUPLE("PrivateBuild"),
+                                    MY_WIDE_STR_TUPLE("FileDescription"),
+#undef MY_WIDE_STR_TUPLE
+                                };
+                                for (uint32_t i = 0; i < RT_ELEMENTS(s_abFields); i++)
+                                {
+                                    size_t          cwcLeft = (sizeof(u) - s_abFields[i].cb - 10) / sizeof(RTUTF16);
+                                    PCRTUTF16       pwc     = u.awcBuf;
+                                    RTUTF16 const   wcFirst = *s_abFields[i].pwsz;
+                                    while (cwcLeft-- > 0)
+                                    {
+                                        if (   pwc[0] == 1 /* wType == text */
+                                            && pwc[1] == wcFirst)
+                                        {
+                                            if (memcmp(pwc + 1, s_abFields[i].pwsz, s_abFields[i].cb + sizeof(RTUTF16)) == 0)
+                                            {
+                                                size_t cwcField = s_abFields[i].cb / sizeof(RTUTF16);
+                                                pwc     += cwcField + 2;
+                                                cwcLeft -= cwcField + 2;
+                                                for (uint32_t iPadding = 0; iPadding < 3; iPadding++, pwc++, cwcLeft--)
+                                                    if (*pwc)
+                                                        break;
+                                                int rc = RTUtf16ValidateEncodingEx(pwc, cwcLeft,
+                                                                                   RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
+                                                if (RT_SUCCESS(rc))
+                                                    SUP_DPRINTF(("    %ls:%*s %ls",
+                                                                 s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", pwc));
+                                                else
+                                                    SUP_DPRINTF(("    %ls:%*s rc=%Rrc",
+                                                                 s_abFields[i].pwsz, cwcField < 15 ? 15 - cwcField : 0, "", rc));
+
+                                                break;
+                                            }
+                                        }
+                                        pwc++;
+                                    }
+                                }
+                            }
+                            else
+                                SUP_DPRINTF(("    NtReadFile @%#llx -> %#x %#x\n", offRead.QuadPart, rcNt, Ios.Status));
+                        }
+                        else
+                            SUP_DPRINTF(("    Resource section not found.\n"));
+                    }
+                }
+                else
+                    SUP_DPRINTF(("    Nt Headers @%#x: Invalid signature\n", offNtHdrs));
+            }
+            else
+                SUP_DPRINTF(("    Nt Headers @%#x: out side buffer\n", offNtHdrs));
+        }
+        else
+            SUP_DPRINTF(("    NtReadFile @0 -> %#x %#x\n", rcNt, Ios.Status));
+        NtClose(hFile);
+    }
+}
+
+
+/**
+ * Scans the Driver directory for drivers which may invade our processes.
+ *
+ * @returns Mask of SUPHARDNT_ADVERSARY_XXX flags.
+ *
+ * @remarks The enumeration of \Driver normally requires administrator
+ *          privileges.  So, the detection we're doing here isn't always gonna
+ *          work just based on that.
+ *
+ * @todo    Find drivers in \FileSystems as well, then we could detect VrNsdDrv
+ *          from ViRobot APT Shield 2.0.
+ */
+static uint32_t supR3HardenedWinFindAdversaries(void)
+{
+    static const struct
+    {
+        uint32_t    fAdversary;
+        const char *pszDriver;
+    } s_aDrivers[] =
+    {
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360,        "SRTSPX" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360,        "SymDS" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360,        "SymEvent" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360,        "SymIRON" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360,        "SymNetS" },
+
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswHwid" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswMonFlt" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswRdr2" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswRvrt" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswSnx" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswsp" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswStm" },
+        { SUPHARDNT_ADVERSARY_AVAST,                "aswVmm" },
+
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmcomm" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmactmon" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmevtmgr" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmtdi" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmebc64" },  /* Titanium internet security, not officescan. */
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmeevw" },   /* Titanium internet security, not officescan. */
+        { SUPHARDNT_ADVERSARY_TRENDMICRO,           "tmciesc" },  /* Titanium internet security, not officescan. */
+
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "cfwids" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "McPvDrv" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfeapfk" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfeavfk" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfefirek" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfehidk" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfencbdc" },
+        { SUPHARDNT_ADVERSARY_MCAFEE,               "mfewfpk" },
+
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "kl1" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "klflt" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "klif" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "KLIM6" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "klkbdflt" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "klmouflt" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "kltdi" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY,            "kneps" },
+
+        { SUPHARDNT_ADVERSARY_MBAM,                 "MBAMWebAccessControl" },
+        { SUPHARDNT_ADVERSARY_MBAM,                 "mbam" },
+        { SUPHARDNT_ADVERSARY_MBAM,                 "mbamchameleon" },
+        { SUPHARDNT_ADVERSARY_MBAM,                 "mwav" },
+        { SUPHARDNT_ADVERSARY_MBAM,                 "mbamswissarmy" },
+
+        { SUPHARDNT_ADVERSARY_AVG,                  "avgfwfd" },
+        { SUPHARDNT_ADVERSARY_AVG,                  "avgtdia" },
+
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINAflt" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINFile" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINKNC" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINProc" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINProt" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSINReg" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "PSKMAD" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSAlpc" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSHttp" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNShttps" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSIds" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSNAHSL" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSpicc" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSPihsw" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSPop3" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSProt" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSPrv" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSSmtp" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNSStrm" },
+        { SUPHARDNT_ADVERSARY_PANDA,                "NNStlsc" },
+
+        { SUPHARDNT_ADVERSARY_MSE,                  "NisDrv" },
+
+        /*{ SUPHARDNT_ADVERSARY_COMODO, "cmdguard" }, file system */
+        { SUPHARDNT_ADVERSARY_COMODO, "inspect" },
+        { SUPHARDNT_ADVERSARY_COMODO, "cmdHlp" },
+
+        { SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN, "dgmaster" }, /* Not verified. */
+    };
+
+    static const struct
+    {
+        uint32_t    fAdversary;
+        PCRTUTF16   pwszFile;
+    } s_aFiles[] =
+    {
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\SysPlant.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysfer.dll" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\sysferThunk.dll" },
+
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ccsetx64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ironx64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtsp64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtspx64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symds64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symefa64.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symelam.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symnets.sys" },
+        { SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\symevent64x86.sys" },
+
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswHwid.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswMonFlt.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRdr2.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswRvrt.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswSnx.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswsp.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswStm.sys" },
+        { SUPHARDNT_ADVERSARY_AVAST, L"\\SystemRoot\\System32\\drivers\\aswVmm.sys" },
+
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmcomm.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmactmon.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmevtmgr.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmtdi.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmebc64.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmeevw.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\tmciesc.sys" },
+        { SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE, L"\\SystemRoot\\System32\\drivers\\sakfile.sys" },  /* Data Loss Prevention, not officescan. */
+        { SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\sakcd.sys" },  /* Data Loss Prevention, not officescan. */
+
+
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\cfwids.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\McPvDrv.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeapfk.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfeavfk.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfefirek.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfehidk.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfencbdc.sys" },
+        { SUPHARDNT_ADVERSARY_MCAFEE, L"\\SystemRoot\\System32\\drivers\\mfewfpk.sys" },
+
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kl1.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klflt.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klif.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klim6.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klkbdflt.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\klmouflt.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kltdi.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\drivers\\kneps.sys" },
+        { SUPHARDNT_ADVERSARY_KASPERSKY, L"\\SystemRoot\\System32\\klfphc.dll" },
+
+        { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\MBAMSwissArmy.sys" },
+        { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mwac.sys" },
+        { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbamchameleon.sys" },
+        { SUPHARDNT_ADVERSARY_MBAM, L"\\SystemRoot\\System32\\drivers\\mbam.sys" },
+
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgrkx64.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgmfx64.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsdrivera.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgidsha.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgtdia.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgloga.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgldx64.sys" },
+        { SUPHARDNT_ADVERSARY_AVG, L"\\SystemRoot\\System32\\drivers\\avgdiska.sys" },
+
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINAflt.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINFile.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINKNC.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProc.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINProt.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSINReg.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\PSKMAD.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSAlpc.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSHttp.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNShttps.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSIds.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSNAHSL.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSpicc.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPihsw.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPop3.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSProt.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSPrv.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSSmtp.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNSStrm.sys" },
+        { SUPHARDNT_ADVERSARY_PANDA, L"\\SystemRoot\\System32\\drivers\\NNStlsc.sys" },
+
+        { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\MpFilter.sys" },
+        { SUPHARDNT_ADVERSARY_MSE, L"\\SystemRoot\\System32\\drivers\\NisDrvWFP.sys" },
+
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmdguard.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmderd.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\inspect.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cmdhlp.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\cfrmd.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\drivers\\hmd.sys" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\guard64.dll" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdvrt64.dll" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdkbd64.dll" },
+        { SUPHARDNT_ADVERSARY_COMODO, L"\\SystemRoot\\System32\\cmdcsr.dll" },
+
+        { SUPHARDNT_ADVERSARY_ZONE_ALARM, L"\\SystemRoot\\System32\\drivers\\vsdatant.sys" },
+        { SUPHARDNT_ADVERSARY_ZONE_ALARM, L"\\SystemRoot\\System32\\AntiTheftCredentialProvider.dll" },
+
+        { SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN, L"\\SystemRoot\\System32\\drivers\\dgmaster.sys" },
+    };
+
+    uint32_t fFound = 0;
+
+    /*
+     * Open the driver object directory.
+     */
+    UNICODE_STRING NtDirName = RTNT_CONSTANT_UNISTR(L"\\Driver");
+
+    OBJECT_ATTRIBUTES ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+
+    HANDLE hDir;
+    NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | FILE_LIST_DIRECTORY, &ObjAttr);
+#ifdef VBOX_STRICT
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(rcNt);
+#endif
+    if (NT_SUCCESS(rcNt))
+    {
+        /*
+         * Enumerate it, looking for the driver.
+         */
+        ULONG    uObjDirCtx = 0;
+        for (;;)
+        {
+            uint32_t    abBuffer[_64K + _1K];
+            ULONG       cbActual;
+            rcNt = NtQueryDirectoryObject(hDir,
+                                          abBuffer,
+                                          sizeof(abBuffer) - 4, /* minus four for string terminator space. */
+                                          FALSE /*ReturnSingleEntry */,
+                                          FALSE /*RestartScan*/,
+                                          &uObjDirCtx,
+                                          &cbActual);
+            if (!NT_SUCCESS(rcNt) || cbActual < sizeof(OBJECT_DIRECTORY_INFORMATION))
+                break;
+
+            POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)abBuffer;
+            while (pObjDir->Name.Length != 0)
+            {
+                WCHAR wcSaved = pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)];
+                pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = '\0';
+
+                for (uint32_t i = 0; i < RT_ELEMENTS(s_aDrivers); i++)
+                    if (RTUtf16ICmpAscii(pObjDir->Name.Buffer, s_aDrivers[i].pszDriver) == 0)
+                    {
+                        fFound |= s_aDrivers[i].fAdversary;
+                        SUP_DPRINTF(("Found driver %s (%#x)\n", s_aDrivers[i].pszDriver, s_aDrivers[i].fAdversary));
+                        break;
+                    }
+
+                pObjDir->Name.Buffer[pObjDir->Name.Length / sizeof(WCHAR)] = wcSaved;
+
+                /* Next directory entry. */
+                pObjDir++;
+            }
+        }
+
+        NtClose(hDir);
+    }
+    else
+        SUP_DPRINTF(("NtOpenDirectoryObject failed on \\Driver: %#x\n", rcNt));
+
+    /*
+     * Look for files.
+     */
+    for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
+    {
+        HANDLE              hFile  = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios    = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+        UNICODE_STRING      UniStrName;
+        UniStrName.Buffer = (WCHAR *)s_aFiles[i].pwszFile;
+        UniStrName.Length = (USHORT)(RTUtf16Len(s_aFiles[i].pwszFile) * sizeof(WCHAR));
+        UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
+        InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+        rcNt = NtCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &ObjAttr, &Ios, NULL /* Allocation Size*/,
+                            FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN,
+                            FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL /*EaBuffer*/, 0 /*EaLength*/);
+        if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
+        {
+            fFound |= s_aFiles[i].fAdversary;
+            NtClose(hFile);
+        }
+    }
+
+    /*
+     * Log details.
+     */
+    SUP_DPRINTF(("supR3HardenedWinFindAdversaries: %#x\n", fFound));
+    for (uint32_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
+        if (fFound & s_aFiles[i].fAdversary)
+            supR3HardenedLogFileInfo(s_aFiles[i].pwszFile, true /* fAdversarial */);
+
+    return fFound;
+}
+
+
 extern "C" int main(int argc, char **argv, char **envp);
 
 /**
@@ -4305,12 +5340,33 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
     RTEXITCODE rcExit = RTEXITCODE_FAILURE;
 
     g_cSuplibHardenedWindowsMainCalls++;
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED;
 
     /*
      * Initialize the NTDLL API wrappers. This aims at bypassing patched NTDLL
      * in all the processes leading up the VM process.
      */
     supR3HardenedWinInitImports();
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED;
+
+    /*
+     * Notify the parent process that we're probably capable of reporting our
+     * own errors.
+     */
+    if (g_ProcParams.hEvtParent || g_ProcParams.hEvtChild)
+    {
+        SUPR3HARDENED_ASSERT(g_fSupEarlyProcessInit);
+
+        g_ProcParams.enmRequest = kSupR3WinChildReq_CloseEvents;
+        NtSetEvent(g_ProcParams.hEvtParent, NULL);
+
+        NtClose(g_ProcParams.hEvtParent);
+        NtClose(g_ProcParams.hEvtChild);
+        g_ProcParams.hEvtParent = NULL;
+        g_ProcParams.hEvtChild  = NULL;
+    }
+    else
+        SUPR3HARDENED_ASSERT(!g_fSupEarlyProcessInit);
 
     /*
      * After having resolved imports we patch the LdrInitializeThunk code so
@@ -4324,6 +5380,7 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
      * SUPHardenedVerfiyImage-win.cpp.)
      */
     supR3HardenedWinInitVersion();
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERSION_INITIALIZED;
 
     /*
      * Convert the arguments to UTF-8 and open the log file if specified.
@@ -4336,6 +5393,19 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
     supR3HardenedOpenLog(&cArgs, papszArgs);
 
     /*
+     * Log information about important system files.
+     */
+    supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\ntdll.dll", false /* fAdversarial */);
+    supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\kernel32.dll", false /* fAdversarial */);
+    supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\KernelBase.dll", false /* fAdversarial */);
+    supR3HardenedLogFileInfo(L"\\SystemRoot\\System32\\apisetschema.dll", false /* fAdversarial */);
+
+    /*
+     * Scan the system for adversaries, logging information about them.
+     */
+    g_fSupAdversaries = supR3HardenedWinFindAdversaries();
+
+    /*
      * Get the executable name.
      */
     DWORD cwcExecName = GetModuleFileNameW(GetModuleHandleW(NULL), g_wszSupLibHardenedExePath,
@@ -4348,8 +5418,8 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
     HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
     if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
-        supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(GetLastError()),
-                              "Error opening the executable: %u (%ls).", GetLastError());
+        supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(RtlGetLastWin32Error()),
+                              "Error opening the executable: %u (%ls).", RtlGetLastWin32Error());
     RT_ZERO(g_SupLibHardenedExeNtPath);
     ULONG cbIgn;
     NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &g_SupLibHardenedExeNtPath,
@@ -4366,6 +5436,16 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
         g_offSupLibHardenedExeNtName--;
 
     /*
+     * If we've done early init already, register the DLL load notification
+     * callback and reinstall the NtDll patches.
+     */
+    if (g_fSupEarlyProcessInit)
+    {
+        supR3HardenedWinRegisterDllNotificationCallback();
+        supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+    }
+
+    /*
      * Call the C/C++ main function.
      */
     SUP_DPRINTF(("Calling main()\n"));
@@ -4378,3 +5458,231 @@ extern "C" void __stdcall suplibHardenedWindowsMain(void)
     suplibHardenedExit(rcExit);
 }
 
+
+/**
+ * Reports an error to the parent process via the process parameter structure.
+ *
+ * @param   pszWhere            Where this error occured, if fatal message. NULL
+ *                              if not message.
+ * @param   enmWhat             Which init operation went wrong if fatal
+ *                              message. kSupInitOp_Invalid if not message.
+ * @param   rc                  The status code to report.
+ * @param   pszFormat           The format string.
+ * @param   va                  The format arguments.
+ */
+DECLHIDDEN(void) supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
+                                                     const char *pszFormat, va_list va)
+{
+    if (pszWhere)
+        RTStrCopy(g_ProcParams.szWhere, sizeof(g_ProcParams.szWhere), pszWhere);
+    else
+        g_ProcParams.szWhere[0] = '\0';
+    RTStrPrintfV(g_ProcParams.szErrorMsg, sizeof(g_ProcParams.szErrorMsg), pszFormat, va);
+    g_ProcParams.enmWhat = enmWhat;
+    g_ProcParams.rc      = RT_SUCCESS(rc) ? VERR_INTERNAL_ERROR_2 : rc;
+    g_ProcParams.enmRequest = kSupR3WinChildReq_Error;
+
+    NtClearEvent(g_ProcParams.hEvtChild);
+    NTSTATUS rcNt = NtSetEvent(g_ProcParams.hEvtParent, NULL);
+    if (NT_SUCCESS(rcNt))
+    {
+        LARGE_INTEGER Timeout;
+        Timeout.QuadPart = -300000000; /* 30 second */
+        NTSTATUS rcNt = NtWaitForSingleObject(g_ProcParams.hEvtChild, FALSE /*Alertable*/, &Timeout);
+    }
+}
+
+
+/**
+ * Routine called by the supR3HardenedEarlyProcessInitThunk assembly routine
+ * when LdrInitializeThunk is executed in during process initialization.
+ *
+ * This initializes the Stub and VM processes, hooking NTDLL APIs and opening
+ * the device driver before any other DLLs gets loaded into the process.  This
+ * greately reduces and controls the trusted code base of the process compared
+ * to opening the driver from SUPR3HardenedMain.  It also avoids issues with so
+ * call protection software that is in the habit of patching half of the ntdll
+ * and kernel32 APIs in the process, making it almost indistinguishable from
+ * software that is up to no good.  Once we've opened vboxdrv, the process
+ * should be locked down so thighly that only kernel software and csrss can mess
+ * with the process.
+ */
+DECLASM(uintptr_t) supR3HardenedEarlyProcessInit(void)
+{
+    /*
+     * When the first thread gets here we wait for the parent to continue with
+     * the process purifications.  The primary thread must execute for image
+     * load notifications to trigger, at least in more recent windows versions.
+     * The old trick of starting a different thread that terminates immediately
+     * thus doesn't work.
+     *
+     * We are not allowed to modify any data at this point because it will be
+     * reset by the child process purification the parent does when we stop. To
+     * sabotage thread creation during purification, and to avoid unnecessary
+     * work for the parent, we reset g_ProcParams before signalling the parent
+     * here.
+     */
+    if (g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
+    {
+        NtTerminateThread(0, 0);
+        return 0x22; /* crash */
+    }
+
+    /* Retrieve the data we need. */
+    uintptr_t uNtDllAddr = ASMAtomicXchgPtrT(&g_ProcParams.uNtDllAddr, 0, uintptr_t);
+    if (!RT_VALID_PTR(uNtDllAddr))
+    {
+        NtTerminateThread(0, 0);
+        return 0x23; /* crash */
+    }
+
+    HANDLE hEvtChild  = g_ProcParams.hEvtChild;
+    HANDLE hEvtParent = g_ProcParams.hEvtParent;
+    if (   hEvtChild  == NULL
+        || hEvtChild  == RTNT_INVALID_HANDLE_VALUE
+        || hEvtParent == NULL
+        || hEvtParent == RTNT_INVALID_HANDLE_VALUE)
+    {
+        NtTerminateThread(0, 0);
+        return 0x24; /* crash */
+    }
+
+    /* Resolve the APIs we need. */
+    PFNNTWAITFORSINGLEOBJECT    pfnNtWaitForSingleObject;
+    PFNNTSETEVENT               pfnNtSetEvent;
+    supR3HardenedWinGetVeryEarlyImports(uNtDllAddr, &pfnNtWaitForSingleObject, &pfnNtSetEvent);
+
+    /* Signal the parent that we're ready for purification. */
+    RT_ZERO(g_ProcParams);
+    g_ProcParams.enmRequest = kSupR3WinChildReq_PurifyChildAndCloseHandles;
+    NTSTATUS rcNt = pfnNtSetEvent(hEvtParent, NULL);
+    if (rcNt != STATUS_SUCCESS)
+        return 0x33; /* crash */
+
+    /* Wait up to 2 mins for the parent to exorcise evil. */
+    LARGE_INTEGER Timeout;
+    Timeout.QuadPart = -1200000000; /* 120 second */
+    rcNt = pfnNtWaitForSingleObject(hEvtChild, FALSE /*Alertable*/, &Timeout);
+    if (rcNt != STATUS_SUCCESS)
+        return 0x34; /* crash */
+
+    /*
+     * We're good to go, work global state and restore process parameters.
+     * Note that we will not restore uNtDllAddr since that is our first defence
+     * against unwanted threads (see above).
+     */
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_INIT_CALLED;
+    g_fSupEarlyProcessInit      = true;
+
+    g_ProcParams.hEvtChild      = hEvtChild;
+    g_ProcParams.hEvtParent     = hEvtParent;
+    g_ProcParams.enmRequest     = kSupR3WinChildReq_Error;
+    g_ProcParams.rc             = VINF_SUCCESS;
+
+    /*
+     * Initialize the NTDLL imports that we consider usable before the
+     * process has been initialized.
+     */
+    supR3HardenedWinInitImportsEarly(uNtDllAddr);
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_IMPORTS_RESOLVED;
+
+    /*
+     * Init g_uNtVerCombined as well as we can at this point.
+     */
+    supR3HardenedWinInitVersion();
+
+    /*
+     * Convert the arguments to UTF-8 so we can open the log file if specified.
+     * We may have to normalize the pointer on older windows version (not w7/64 +).
+     * Note! This leaks memory at present.
+     */
+    PRTL_USER_PROCESS_PARAMETERS pUserProcParams = NtCurrentPeb()->ProcessParameters;
+    UNICODE_STRING CmdLineStr = pUserProcParams->CommandLine;
+    if (   CmdLineStr.Buffer != NULL
+        && !(pUserProcParams->Flags & RTL_USER_PROCESS_PARAMS_FLAG_NORMALIZED) )
+        CmdLineStr.Buffer = (WCHAR *)((uintptr_t)CmdLineStr.Buffer + (uintptr_t)pUserProcParams);
+    int    cArgs;
+    char **papszArgs = suplibCommandLineToArgvWStub(CmdLineStr.Buffer, CmdLineStr.Length / sizeof(WCHAR), &cArgs);
+    supR3HardenedOpenLog(&cArgs, papszArgs);
+    SUP_DPRINTF(("supR3HardenedVmProcessInit: uNtDllAddr=%p\n", uNtDllAddr));
+
+    /*
+     * Set up the direct system calls so we can more easily hook NtCreateSection.
+     */
+    supR3HardenedWinInitSyscalls(true /*fReportErrors*/);
+
+    /*
+     * Determine the executable path and name.  Will NOT determine the windows style
+     * executable path here as we don't need it.
+     */
+    SIZE_T cbActual = 0;
+    rcNt = NtQueryVirtualMemory(NtCurrentProcess(), &g_ProcParams, MemorySectionName, &g_SupLibHardenedExeNtPath,
+                                sizeof(g_SupLibHardenedExeNtPath) - sizeof(WCHAR), &cbActual);
+    if (   !NT_SUCCESS(rcNt)
+        || g_SupLibHardenedExeNtPath.UniStr.Length == 0
+        || g_SupLibHardenedExeNtPath.UniStr.Length & 1)
+        supR3HardenedFatal("NtQueryVirtualMemory/MemorySectionName failed in supR3HardenedVmProcessInit: %#x\n", rcNt);
+
+    /* The NT executable name offset / dir path length. */
+    g_offSupLibHardenedExeNtName = g_SupLibHardenedExeNtPath.UniStr.Length / sizeof(WCHAR);
+    while (   g_offSupLibHardenedExeNtName > 1
+           && g_SupLibHardenedExeNtPath.UniStr.Buffer[g_offSupLibHardenedExeNtName - 1] != '\\' )
+        g_offSupLibHardenedExeNtName--;
+
+    /*
+     * Initialize the image verification stuff (hooks LdrLoadDll and NtCreateSection).
+     */
+    supR3HardenedWinInit(0, false /*fAvastKludge*/);
+
+    /*
+     * Open the driver.
+     */
+    if (cArgs >= 1 && suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_1_ARG0) == 0)
+    {
+        SUP_DPRINTF(("supR3HardenedVmProcessInit: Opening vboxdrv stub...\n"));
+        supR3HardenedWinOpenStubDevice();
+    }
+    else if (cArgs >= 1 && suplibHardenedStrCmp(papszArgs[0], SUPR3_RESPAWN_2_ARG0) == 0)
+    {
+        SUP_DPRINTF(("supR3HardenedVmProcessInit: Opening vboxdrv...\n"));
+        supR3HardenedMainOpenDevice();
+    }
+    else
+        supR3HardenedFatal("Unexpected first argument '%s'!\n", papszArgs[0]);
+    g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_EARLY_DEVICE_OPENED;
+
+    /*
+     * Reinstall the NtDll patches since there is a slight possibility that
+     * someone undid them while we where busy opening the device.
+     */
+    supR3HardenedWinReInstallHooks(false /*fFirstCall */);
+
+    /*
+     * Restore the LdrInitializeThunk code so we can initialize the process
+     * normally when we return.
+     */
+    SUP_DPRINTF(("supR3HardenedVmProcessInit: Restoring LdrInitializeThunk...\n"));
+    PSUPHNTLDRCACHEENTRY pLdrEntry;
+    int rc = supHardNtLdrCacheOpen("ntdll.dll", &pLdrEntry);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
+
+    uint8_t *pbBits;
+    rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
+
+    RTLDRADDR uValue;
+    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, uNtDllAddr, UINT32_MAX, "LdrInitializeThunk", &uValue);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("supR3HardenedVmProcessInit: Failed to find LdrInitializeThunk (%Rrc).\n", rc);
+
+    PVOID pvLdrInitThunk = (PVOID)(uintptr_t)uValue;
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READWRITE));
+    memcpy(pvLdrInitThunk, pbBits + ((uintptr_t)uValue - uNtDllAddr), 16);
+    SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READ));
+
+    SUP_DPRINTF(("supR3HardenedVmProcessInit: Returning to LdrInitializeThunk...\n"));
+    return (uintptr_t)pvLdrInitThunk;
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
index 0b9c996..d6440e5 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
@@ -31,50 +31,82 @@
 %include "iprt/asmdefs.mac"
 
 
-; External data.
-extern NAME(g_pfnNtCreateSectionJmpBack)
+; External code.
+extern NAME(supR3HardenedEarlyProcessInit)
 
 
 BEGINCODE
 
+
+;;
+; Alternative code for LdrInitializeThunk that performs the early process startup
+; for the Stub and VM processes.
 ;
-; 64-bit
+; This does not concern itself with any arguments on stack or in registers that
+; may be passed to the LdrIntializeThunk routine as we just save and restore
+; them all before we restart the restored LdrInitializeThunk routine.
 ;
-%ifdef RT_ARCH_AMD64
- %macro supR3HardenedJmpBack_NtCreateSection_Xxx 1
- BEGINPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
-        SEH64_END_PROLOGUE
-        ; The code we replaced.
-        mov     r10, rcx
-        mov     eax, %1
+; @sa supR3HardenedEarlyProcessInit
+;
+BEGINPROC supR3HardenedEarlyProcessInitThunk
+        ;
+        ; Prologue.
+        ;
 
-        ; Jump back to the original code.
-        jmp     [NAME(g_pfnNtCreateSectionJmpBack) wrt RIP]
- ENDPROC   supR3HardenedJmpBack_NtCreateSection_ %+ %1
- %endm
- %define SYSCALL(a_Num) supR3HardenedJmpBack_NtCreateSection_Xxx a_Num
- %include "NtCreateSection-template-amd64-syscall-type-1.h"
+        ; Reserve space for the "return" address.
+        push    0
 
+        ; Create a stack frame, saving xBP.
+        push    xBP
+        SEH64_PUSH_xBP
+        mov     xBP, xSP
+        SEH64_SET_FRAME_xBP 0 ; probably wrong...
+
+        ; Save all volatile registers.
+        push    xAX
+        push    xCX
+        push    xDX
+%ifdef RT_ARCH_AMD64
+        push    r8
+        push    r9
+        push    r10
+        push    r11
 %endif
 
+        ; Reserve spill space and align the stack.
+        sub     xSP, 20h
+        and     xSP, ~0fh
+        SEH64_END_PROLOGUE
 
-;
-; 32-bit.
-;
-%ifdef RT_ARCH_X86
- %macro supR3HardenedJmpBack_NtCreateSection_Xxx 1
- BEGINPROC supR3HardenedJmpBack_NtCreateSection_ %+ %1
-        ; The code we replaced.
-        mov     eax, %1
-
-        ; Jump back to the original code.
-        jmp     [NAME(g_pfnNtCreateSectionJmpBack)]
- ENDPROC   supR3HardenedJmpBack_NtCreateSection_ %+ %1
- %endm
- %define SYSCALL(a_Num) supR3HardenedJmpBack_NtCreateSection_Xxx a_Num
- %include "NtCreateSection-template-x86-syscall-type-1.h"
+        ;
+        ; Call the C/C++ code that does the actual work.  This returns the
+        ; resume address in xAX, which we put in the "return" stack position.
+        ;
+        call    NAME(supR3HardenedEarlyProcessInit)
+        mov     [xBP + xCB], xAX
 
+        ;
+        ; Restore volatile registers.
+        ;
+        mov     xAX, [xBP - xCB*1]
+        mov     xCX, [xBP - xCB*2]
+        mov     xDX, [xBP - xCB*3]
+%ifdef RT_ARCH_AMD64
+        mov     r8,  [xBP - xCB*4]
+        mov     r9,  [xBP - xCB*5]
+        mov     r10, [xBP - xCB*6]
+        mov     r11, [xBP - xCB*7]
 %endif
+        ;
+        ; Use the leave instruction to restore xBP and set up xSP to point at
+        ; the resume address. Then use the 'ret' instruction to resume process
+        ; initializaton.
+        ;
+        leave
+        ret
+ENDPROC   supR3HardenedEarlyProcessInitThunk
+
+
 
 ;;
 ; Composes a standard call name.
@@ -84,6 +116,9 @@ BEGINCODE
  %define SUPHNTIMP_STDCALL_NAME(a,b) NAME(a)
 %endif
 
+;; Concats two litterals.
+%define SUPHNTIMP_CONCAT(a,b) a %+ b
+
 
 ;;
 ; Import data and code for an API call.
@@ -91,9 +126,10 @@ BEGINCODE
 ; @param 1  The plain API name.
 ; @param 2  The parameter frame size on x86. Multiple of dword.
 ; @param 3  Non-zero expression if system call.
+; @param 4  Non-zero expression if early available call
 ;
 %define SUPHNTIMP_SYSCALL 1
-%macro SupHardNtImport 3
+%macro SupHardNtImport 4
         ;
         ; The data.
         ;
@@ -145,11 +181,24 @@ BEGINPROC %1 %+ _SyscallType2
 ENDPROC %1 %+ _SyscallType2
   %endif
 %endif
+
+%if %4 == 0
+global NAME(SUPHNTIMP_CONCAT(%1,_Early))
+NAME(SUPHNTIMP_CONCAT(%1,_Early)):
+        int3
+ %ifdef RT_ARCH_AMD64
+        ret
+ %else
+        ret     %2
+ %endif
+%endif
 %endmacro
 
 %define SUPHARNT_COMMENT(a_Comment)
-%define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, SUPHNTIMP_SYSCALL
-%define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, 0
+%define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86)       SupHardNtImport a_Name, a_cbParamsX86, SUPHNTIMP_SYSCALL, 1
+%define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)       SupHardNtImport a_Name, a_cbParamsX86, 0, 0
+%define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) SupHardNtImport a_Name, a_cbParamsX86, 0, 1
+%define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)
 %include "import-template-ntdll.h"
 %include "import-template-kernel32.h"
 
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
index 0d979b3..99a1751 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
@@ -47,10 +47,13 @@
 
 #define VBOX_HARDENED_STUB_WITHOUT_IMPORTS
 #ifdef VBOX_HARDENED_STUB_WITHOUT_IMPORTS
-# define SUPHNTIMP_ERROR(a_id, a_szWhere, a_enmOp, a_rc, ...) \
-    do { static const char s_szWhere[] = a_szWhere; *(char *)(uintptr_t)(a_id) += 1; __debugbreak(); } while (0)
+# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
+    do { \
+        if (a_fReportErrors) supR3HardenedFatalMsg(a_szWhere, a_enmOp, a_rc, __VA_ARGS__); \
+        else { static const char s_szWhere[] = a_szWhere; *(char *)(uintptr_t)(a_id) += 1; __debugbreak(); } \
+    } while (0)
 #else
-# define SUPHNTIMP_ERROR(a_id, a_szWhere, a_enmOp, a_rc, ...) \
+# define SUPHNTIMP_ERROR(a_fReportErrors, a_id, a_szWhere, a_enmOp, a_rc, ...) \
     supR3HardenedFatalMsg(a_szWhere, a_enmOp, a_rc, __VA_ARGS__)
 
 #endif
@@ -68,6 +71,12 @@ typedef struct SUPHNTIMPFUNC
     const char         *pszName;
     /** Where to store the function address (think __imp_ApiName). */
     PFNRT              *ppfnImport;
+    /** Pointer to an early dummy function for imports that aren't available
+     * during early process initialization. */
+    PFNRT               pfnEarlyDummy;
+    /** Indicates whether this is an optional import and failure to locate it
+     * should set it to NULL instead of freaking out. */
+    bool                fOptional;
 } SUPHNTIMPFUNC;
 /** Pointer to an import table entry.  */
 typedef SUPHNTIMPFUNC const *PCSUPHNTIMPFUNC;
@@ -138,6 +147,9 @@ typedef struct SUPHNTIMPDLL
      *  (indexes into paoffExports). */
     uint16_t const         *pau16NameOrdinals;
 
+    /** Number of patched export table entries. */
+    uint32_t                cPatchedExports;
+
 } SUPHNTIMPDLL;
 /** Pointer to an import DLL entry. */
 typedef SUPHNTIMPDLL *PSUPHNTIMPDLL;
@@ -147,13 +159,17 @@ typedef SUPHNTIMPDLL *PSUPHNTIMPDLL;
 /*
  * Declare assembly symbols.
  */
-#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
     extern PFNRT    RT_CONCAT(g_pfn, a_Name);
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86)  SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)
 #define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
-    SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+    SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
     extern uint32_t RT_CONCAT(g_uApiNo, a_Name); \
     extern FNRT     RT_CONCAT(a_Name, _SyscallType1); \
     extern FNRT     RT_CONCAT(a_Name, _SyscallType2);
+#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+    extern PFNRT    RT_CONCAT(g_pfn, a_Name); \
+    extern FNRT     RT_CONCAT(a_Name, _Early);
 
 RT_C_DECLS_BEGIN
 #include "import-template-ntdll.h"
@@ -164,9 +180,17 @@ RT_C_DECLS_END
  * Import functions.
  */
 #undef SUPHARNT_IMPORT_SYSCALL
+#undef SUPHARNT_IMPORT_STDCALL_EARLY
+#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
 #undef SUPHARNT_IMPORT_STDCALL
-#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) { #a_Name, &RT_CONCAT(g_pfn, a_Name) },
-#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) { #a_Name, &RT_CONCAT(g_pfn, a_Name) },
+#define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
+    { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86) \
+    { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, false },
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) \
+    { #a_Name, &RT_CONCAT(g_pfn, a_Name), NULL, true },
+#define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
+    { #a_Name, &RT_CONCAT(g_pfn, a_Name), RT_CONCAT(a_Name,_Early), false },
 static const SUPHNTIMPFUNC g_aSupNtImpNtDllFunctions[] =
 {
 #include "import-template-ntdll.h"
@@ -184,6 +208,8 @@ static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
  */
 #undef SUPHARNT_IMPORT_SYSCALL
 #undef SUPHARNT_IMPORT_STDCALL
+#undef SUPHARNT_IMPORT_STDCALL_EARLY
+#undef SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL
 #ifdef RT_ARCH_AMD64
 # define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
     { NULL, NULL },
@@ -195,6 +221,8 @@ static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
 # define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
     { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name,_SyscallType1), &RT_CONCAT(a_Name, _SyscallType2), a_cbParamsX86 },
 #endif
+#define SUPHARNT_IMPORT_STDCALL_EARLY(a_Name, a_cbParamsX86)          SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
+#define SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(a_Name, a_cbParamsX86) SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86)
 static const SUPHNTIMPSYSCALL g_aSupNtImpNtDllSyscalls[] =
 {
 #include "import-template-ntdll.h"
@@ -203,6 +231,7 @@ static const SUPHNTIMPSYSCALL g_aSupNtImpNtDllSyscalls[] =
 
 /**
  * All the DLLs we import from.
+ * @remarks Code ASSUMES that ntdll is the first entry.
  */
 static SUPHNTIMPDLL g_aSupNtImpDlls[] =
 {
@@ -241,12 +270,12 @@ static void supR3HardenedFindOrLoadModule(PSUPHNTIMPDLL pDll)
     if (!pDll->cImports)
         pDll->pbImageBase = NULL; /* optional */
     else
-        SUPHNTIMP_ERROR(1, "supR3HardenedFindOrLoadModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+        SUPHNTIMP_ERROR(false, 1, "supR3HardenedFindOrLoadModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
                         "Failed to locate %ls", pDll->pwszName);
 #else
     HMODULE hmod = GetModuleHandleW(pDll->pwszName);
     if (RT_UNLIKELY(!hmod && pDll->cImports))
-        SUPHNTIMP_ERROR(1, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+        SUPHNTIMP_ERROR(true, 1, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
                         "Failed to locate %ls", pDll->pwszName);
     pDll->pbImageBase = (uint8_t *)hmod;
 #endif
@@ -265,22 +294,22 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
     {
         offNtHdrs = pMzHdr->e_lfanew;
         if (offNtHdrs > _2K)
-            SUPHNTIMP_ERROR(2, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+            SUPHNTIMP_ERROR(false, 2, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
                             "%ls: e_lfanew=%#x, expected a lower value", pDll->pwszName, offNtHdrs);
     }
     pDll->pNtHdrs = pNtHdrs = (PIMAGE_NT_HEADERS)&pDll->pbImageBase[offNtHdrs];
 
     if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
-        SUPHNTIMP_ERROR(3, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 3, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: Invalid PE signature: %#x", pDll->pwszName, pNtHdrs->Signature);
     if (pNtHdrs->FileHeader.SizeOfOptionalHeader != sizeof(pNtHdrs->OptionalHeader))
-        SUPHNTIMP_ERROR(4, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 4, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: Unexpected optional header size: %#x", pDll->pwszName, pNtHdrs->FileHeader.SizeOfOptionalHeader);
     if (pNtHdrs->OptionalHeader.Magic != RT_CONCAT3(IMAGE_NT_OPTIONAL_HDR,ARCH_BITS,_MAGIC))
-        SUPHNTIMP_ERROR(5, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 5, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: Unexpected optional header magic: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.Magic);
     if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
-        SUPHNTIMP_ERROR(6, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 6, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: Unexpected number of RVA and sizes: %#x", pDll->pwszName, pNtHdrs->OptionalHeader.NumberOfRvaAndSizes);
 
     pDll->offNtHdrs      = offNtHdrs;
@@ -297,7 +326,7 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
         || ExpDir.VirtualAddress < pDll->offEndSectHdrs
         || ExpDir.VirtualAddress >= pNtHdrs->OptionalHeader.SizeOfImage
         || ExpDir.VirtualAddress + ExpDir.Size > pNtHdrs->OptionalHeader.SizeOfImage)
-        SUPHNTIMP_ERROR(7, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 7, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: Missing or invalid export directory: %#lx LB %#x", pDll->pwszName, ExpDir.VirtualAddress, ExpDir.Size);
     pDll->offExportDir = ExpDir.VirtualAddress;
     pDll->cbExportDir  = ExpDir.Size;
@@ -308,7 +337,7 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
         || pExpDir->NumberOfFunctions <  1
         || pExpDir->NumberOfNames     >= _1M
         || pExpDir->NumberOfNames     <  1)
-        SUPHNTIMP_ERROR(8, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+        SUPHNTIMP_ERROR(false, 8, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                         "%ls: NumberOfNames or/and NumberOfFunctions are outside the expected range: nof=%#x non=%#x\n",
                         pDll->pwszName, pExpDir->NumberOfFunctions, pExpDir->NumberOfNames);
     pDll->cNamedExports = pExpDir->NumberOfNames;
@@ -317,27 +346,27 @@ static void supR3HardenedParseModule(PSUPHNTIMPDLL pDll)
     if (   pExpDir->AddressOfFunctions < pDll->offEndSectHdrs
         || pExpDir->AddressOfFunctions >= pNtHdrs->OptionalHeader.SizeOfImage
         || pExpDir->AddressOfFunctions + pDll->cExports * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
-           SUPHNTIMP_ERROR(9, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+           SUPHNTIMP_ERROR(false, 9, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                            "%ls: Bad AddressOfFunctions: %#x\n", pDll->pwszName, pExpDir->AddressOfFunctions);
     pDll->paoffExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfFunctions];
 
     if (   pExpDir->AddressOfNames < pDll->offEndSectHdrs
         || pExpDir->AddressOfNames >= pNtHdrs->OptionalHeader.SizeOfImage
         || pExpDir->AddressOfNames + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
-           SUPHNTIMP_ERROR(10, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+           SUPHNTIMP_ERROR(false, 10, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                            "%ls: Bad AddressOfNames: %#x\n", pDll->pwszName, pExpDir->AddressOfNames);
     pDll->paoffNamedExports = (uint32_t const *)&pDll->pbImageBase[pExpDir->AddressOfNames];
 
     if (   pExpDir->AddressOfNameOrdinals < pDll->offEndSectHdrs
         || pExpDir->AddressOfNameOrdinals >= pNtHdrs->OptionalHeader.SizeOfImage
         || pExpDir->AddressOfNameOrdinals + pExpDir->NumberOfNames * sizeof(uint32_t) > pNtHdrs->OptionalHeader.SizeOfImage)
-           SUPHNTIMP_ERROR(11, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
+           SUPHNTIMP_ERROR(false, 11, "supR3HardenedParseModule", kSupInitOp_Misc, VERR_INVALID_EXE_SIGNATURE,
                            "%ls: Bad AddressOfNameOrdinals: %#x\n", pDll->pwszName, pExpDir->AddressOfNameOrdinals);
     pDll->pau16NameOrdinals = (uint16_t const *)&pDll->pbImageBase[pExpDir->AddressOfNameOrdinals];
 }
 
 
-static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport)
+static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, bool fReportErrors)
 {
     /*
      * Binary search.
@@ -349,7 +378,7 @@ static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUN
         uint32_t iCur        = iStart + (iEnd - iStart) / 2;
         uint32_t offExpName  = pDll->paoffNamedExports[iCur];
         if (RT_UNLIKELY(offExpName < pDll->offEndSectHdrs || offExpName >= pDll->cbImage))
-            SUPHNTIMP_ERROR(12, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
+            SUPHNTIMP_ERROR(fReportErrors, 12, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
                             "%ls: Bad export name entry: %#x (iCur=%#x)", pDll->pwszName, offExpName, iCur);
 
         const char *pszExpName = (const char *)&pDll->pbImageBase[offExpName];
@@ -364,36 +393,37 @@ static const char *supR3HardenedResolveImport(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUN
             if (iExpOrdinal < pDll->cExports)
             {
                 uint32_t offExport = pDll->paoffExports[iExpOrdinal];
-                if (offExport < pDll->cbImage)
-                {
-                    if (offExport - pDll->offExportDir >= pDll->cbExportDir)
-                    {
-                        *pImport->ppfnImport = (PFNRT)&pDll->pbImageBase[offExport];
-                        return NULL;
-                    }
 
-                    /* Forwarder. */
-                    return (const char *)&pDll->pbImageBase[offExport];
+                /* detect export table patching. */
+                if (offExport >= pDll->cbImage)
+                    pDll->cPatchedExports++;
+
+                if (offExport - pDll->offExportDir >= pDll->cbExportDir)
+                {
+                    *pImport->ppfnImport = (PFNRT)&pDll->pbImageBase[offExport];
+                    return NULL;
                 }
-                SUPHNTIMP_ERROR(13, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
-                                "%ls: The export RVA for '%s' is out of bounds: %#x (SizeOfImage %#x)",
-                                 pDll->pwszName, offExport, pDll->cbImage);
+
+                /* Forwarder. */
+                return (const char *)&pDll->pbImageBase[offExport];
             }
-            SUPHNTIMP_ERROR(14, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
+            SUPHNTIMP_ERROR(fReportErrors, 14, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_BAD_EXE_FORMAT,
                             "%ls: Name ordinal for '%s' is out of bounds: %#x (max %#x)",
                             pDll->pwszName, iExpOrdinal, pDll->cExports);
             return NULL;
         }
     }
 
-    SUPHNTIMP_ERROR(15, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
-                    "%ls: Failed to resolve '%s'.", pDll->pwszName, pImport->pszName);
+    if (!pImport->fOptional)
+        SUPHNTIMP_ERROR(fReportErrors, 15, "supR3HardenedResolveImport", kSupInitOp_Misc, VERR_SYMBOL_NOT_FOUND,
+                        "%ls: Failed to resolve '%s'.", pDll->pwszName, pImport->pszName);
+    *pImport->ppfnImport = NULL;
     return NULL;
 }
 
 
 static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImport, PCSUPHNTIMPSYSCALL pSyscall,
-                                       PSUPHNTLDRCACHEENTRY pLdrEntry, uint8_t *pbBits)
+                                       PSUPHNTLDRCACHEENTRY pLdrEntry, uint8_t *pbBits, bool fReportErrors)
 {
     /*
      * Skip non-syscall entries.
@@ -408,7 +438,7 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
     int rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)pDll->pbImageBase, UINT32_MAX, pImport->pszName, &uValue);
     if (RT_FAILURE(rc))
     {
-        SUPHNTIMP_ERROR(16, "supR3HardenedDirectSyscall", kSupInitOp_Misc, rc,
+        SUPHNTIMP_ERROR(fReportErrors, 16, "supR3HardenedDirectSyscall", kSupInitOp_Misc, rc,
                         "%s: RTLdrGetSymbolEx failed on %s: %Rrc", pDll->pszName, pImport->pszName, rc);
         return;
     }
@@ -513,12 +543,127 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
      */
     volatile uint8_t abCopy[16];
     memcpy((void *)&abCopy[0], pbFunction, sizeof(abCopy));
-    SUPHNTIMP_ERROR(17, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+    SUPHNTIMP_ERROR(fReportErrors, 17, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
                     "%ls: supHardNtLdrCacheOpen failed: '%s': %.16Rhxs",
-                    g_aSupNtImpDlls[iDll].pwszName, pImport->pszName, &abCopy[0]);
+                    pDll->pwszName, pImport->pszName, &abCopy[0]);
+}
+
+
+/**
+ * Check out system calls and do the directly instead of via NtDll.
+ *
+ * We need to have access to the on disk NTDLL.DLL file as we do not trust the
+ * stuff we find in memory.  Too early to verify signatures though.
+ *
+ * @param   fReportErrors       Whether we've got the machinery for reporting
+ *                              errors going already.
+ */
+DECLHIDDEN(void) supR3HardenedWinInitSyscalls(bool fReportErrors)
+{
+    for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+        if (g_aSupNtImpDlls[iDll].paSyscalls)
+        {
+            PSUPHNTLDRCACHEENTRY pLdrEntry;
+            int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
+            if (RT_SUCCESS(rc))
+            {
+                uint8_t *pbBits;
+                rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+                                                   NULL /*pErrInfo*/);
+                if (RT_SUCCESS(rc))
+                {
+                    for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+                        supR3HardenedDirectSyscall(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
+                                                   &g_aSupNtImpDlls[iDll].paSyscalls[i], pLdrEntry, pbBits, fReportErrors);
+                }
+                else
+                    SUPHNTIMP_ERROR(fReportErrors, 20, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+                                    "%ls: supHardNtLdrCacheEntryGetBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+            }
+            else
+                SUPHNTIMP_ERROR(fReportErrors, 21, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
+                                "%ls: supHardNtLdrCacheOpen failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+        }
+}
+
+
+/**
+ * Resolves a few NtDll functions we need before child purification is executed.
+ *
+ * We must not permanently modify any global data here.
+ *
+ * @param   uNtDllAddr          The address of the NTDLL.
+ */
+DECLHIDDEN(void) supR3HardenedWinGetVeryEarlyImports(uintptr_t uNtDllAddr,
+                                                     PFNNTWAITFORSINGLEOBJECT *ppfnNtWaitForSingleObject,
+                                                     PFNNTSETEVENT *ppfnNtSetEvent)
+{
+    /*
+     * NTDLL is the first entry in the list.  Save it and do the parsing.
+     */
+    SUPHNTIMPDLL SavedDllEntry = g_aSupNtImpDlls[0];
+
+    g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
+    supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
+
+    /*
+     * Create a temporary import table for the requested APIs and resolve them.
+     */
+    SUPHNTIMPFUNC aImports[] =
+    {
+        { "NtWaitForSingleObject",  (PFNRT *)ppfnNtWaitForSingleObject,     NULL, false },
+        { "NtSetEvent",             (PFNRT *)ppfnNtSetEvent,                NULL, false },
+    };
+
+    for (uint32_t i = 0; i < RT_ELEMENTS(aImports); i++)
+        {
+            const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &aImports[i], false);
+            if (pszForwarder)
+                SUPHNTIMP_ERROR(false, 31, "supR3HardenedWinGetVeryEarlyImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+                                "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
+        }
+
+    /*
+     * Restore the NtDll entry.
+     */
+    g_aSupNtImpDlls[0] = SavedDllEntry;
 }
 
 
+/**
+ * Resolves NtDll functions we can trust calling before process init.
+ *
+ * @param   uNtDllAddr          The address of the NTDLL.
+ */
+DECLHIDDEN(void) supR3HardenedWinInitImportsEarly(uintptr_t uNtDllAddr)
+{
+    /*
+     * NTDLL is the first entry in the list.
+     */
+    g_aSupNtImpDlls[0].pbImageBase = (uint8_t const *)uNtDllAddr;
+    supR3HardenedParseModule(&g_aSupNtImpDlls[0]);
+    for (uint32_t i = 0; i < g_aSupNtImpDlls[0].cImports; i++)
+        if (!g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy)
+        {
+            const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &g_aSupNtImpDlls[0].paImports[i], false);
+            if (pszForwarder)
+                SUPHNTIMP_ERROR(false, 32, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+                                "ntdll: Failed to resolve forwarder '%s'.", pszForwarder);
+        }
+        else
+            *g_aSupNtImpDlls[0].paImports[i].ppfnImport = g_aSupNtImpDlls[0].paImports[i].pfnEarlyDummy;
+
+    /*
+     * Pointer the other imports at the early init stubs.
+     */
+    for (uint32_t iDll = 1; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+        for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+            if (!g_aSupNtImpDlls[iDll].paImports[i].fOptional)
+                *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = g_aSupNtImpDlls[iDll].paImports[i].pfnEarlyDummy;
+            else
+                *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = NULL;
+}
+
 
 /**
  * Resolves imported functions, esp. system calls from NTDLL.
@@ -547,7 +692,8 @@ DECLHIDDEN(void) supR3HardenedWinInitImports(void)
     for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
         for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
         {
-            const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i]);
+            const char *pszForwarder = supR3HardenedResolveImport(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
+                                                                  false);
             if (pszForwarder)
             {
                 const char *pszDot = strchr(pszForwarder, '.');
@@ -555,53 +701,103 @@ DECLHIDDEN(void) supR3HardenedWinInitImports(void)
                 SUPHNTIMPFUNC  Tmp = g_aSupNtImpDlls[iDll].paImports[i];
                 Tmp.pszName = pszDot + 1;
                 if (cchDllName == sizeof("ntdll") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("ntdll")) == 0)
-                    supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &Tmp);
+                    supR3HardenedResolveImport(&g_aSupNtImpDlls[0], &Tmp, false);
                 else if (cchDllName == sizeof("kernelbase") - 1 && RTStrNICmp(pszForwarder, RT_STR_TUPLE("kernelbase")) == 0)
-                    supR3HardenedResolveImport(&g_aSupNtImpDlls[1], &Tmp);
+                    supR3HardenedResolveImport(&g_aSupNtImpDlls[1], &Tmp, false);
                 else
-                    SUPHNTIMP_ERROR(18, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
+                    SUPHNTIMP_ERROR(false, 18, "supR3HardenedWinInitImports", kSupInitOp_Misc, VERR_MODULE_NOT_FOUND,
                                     "%ls: Failed to resolve forwarder '%s'.", g_aSupNtImpDlls[iDll].pwszName, pszForwarder);
             }
         }
 
     /*
-     * Check out system calls and try do them directly if we can.
-     * In order to do this though, we need to access the DLL on disk as we
-     * cannot trust the memory content to be unpatched.
-     *
-     * Note! It's too early to validate any signatures.
+     * Do system calls directly.
+     */
+    supR3HardenedWinInitSyscalls(false);
+
+    /*
+     * Use the on disk image to avoid export table patching.  Currently
+     * ignoring errors here as can live normally without this step.
      */
     for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
-        if (g_aSupNtImpDlls[iDll].paSyscalls)
+        if (g_aSupNtImpDlls[iDll].cPatchedExports > 0)
+        {
+            PSUPHNTLDRCACHEENTRY pLdrEntry;
+            int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
+            if (RT_SUCCESS(rc))
+            {
+                uint8_t *pbBits;
+                rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+                                                   NULL /*pErrInfo*/);
+                if (RT_SUCCESS(rc))
+                    for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
+                    {
+                        RTLDRADDR uValue;
+                        rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
+                                              UINT32_MAX, g_aSupNtImpDlls[iDll].paImports[i].pszName, &uValue);
+                        if (RT_SUCCESS(rc))
+                            *g_aSupNtImpDlls[iDll].paImports[i].ppfnImport = (PFNRT)(uintptr_t)uValue;
+                    }
+            }
+        }
+
+
+#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
+    *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
+#endif
+}
+
+
+/**
+ * Gets the address of a procedure in a DLL, ignoring our own syscall
+ * implementations.
+ *
+ * Currently restricted to NTDLL and KERNEL32
+ *
+ * @returns The procedure address.
+ * @param   pszDll          The DLL name.
+ * @param   pszProcedure    The procedure name.
+ */
+DECLHIDDEN(PFNRT) supR3HardenedWinGetRealDllSymbol(const char *pszDll, const char *pszProcedure)
+{
+    /*
+     * Look the DLL up in the import DLL table.
+     */
+    for (uint32_t iDll = 0; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
+        if (RTStrICmp(g_aSupNtImpDlls[iDll].pszName, pszDll) == 0)
         {
+
             PSUPHNTLDRCACHEENTRY pLdrEntry;
             int rc = supHardNtLdrCacheOpen(g_aSupNtImpDlls[iDll].pszName, &pLdrEntry);
             if (RT_SUCCESS(rc))
             {
                 uint8_t *pbBits;
-                rc = supHardNtLdrCacheEntryAllocBits(pLdrEntry, &pbBits, NULL);
+                rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL,
+                                                   NULL /*pErrInfo*/);
                 if (RT_SUCCESS(rc))
                 {
-                    rc = RTLdrGetBits(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase, NULL, NULL);
+                    RTLDRADDR uValue;
+                    rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, (uintptr_t)g_aSupNtImpDlls[iDll].pbImageBase,
+                                          UINT32_MAX, pszProcedure, &uValue);
                     if (RT_SUCCESS(rc))
-                        for (uint32_t i = 0; i < g_aSupNtImpDlls[iDll].cImports; i++)
-                            supR3HardenedDirectSyscall(&g_aSupNtImpDlls[iDll], &g_aSupNtImpDlls[iDll].paImports[i],
-                                                       &g_aSupNtImpDlls[iDll].paSyscalls[i], pLdrEntry, pbBits);
-                    else
-                        SUPHNTIMP_ERROR(19, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
-                                        "%ls: RTLdrGetBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+                        return (PFNRT)(uintptr_t)uValue;
+                    SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: Error getting %s in %s -> %Rrc\n", pszProcedure, pszDll, rc));
                 }
                 else
-                    SUPHNTIMP_ERROR(20, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
-                                    "%ls: supHardNtLdrCacheEntryAllocBits failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+                    SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheEntryAllocBits failed on %s: %Rrc\n",
+                                 pszDll, rc));
             }
             else
-                SUPHNTIMP_ERROR(21, "supR3HardenedWinInitImports", kSupInitOp_Misc, rc,
-                                "%ls: supHardNtLdrCacheOpen failed: %Rrc '%s'.", g_aSupNtImpDlls[iDll].pwszName, rc);
+                SUP_DPRINTF(("supR3HardenedWinGetRealDllSymbol: supHardNtLdrCacheOpen failed on %s: %Rrc\n",
+                             pszDll, rc));
+
+            /* Complications, just call GetProcAddress. */
+            if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+                return (PFNRT)GetProcAddress(GetModuleHandleW(g_aSupNtImpDlls[iDll].pwszName), pszProcedure);
+            return NULL;
         }
 
-#if 0 /* Win7/32 ntdll!LdrpDebugFlags. */
-    *(uint8_t *)&g_aSupNtImpDlls[0].pbImageBase[0xdd770] = 0x3;
-#endif
+    supR3HardenedFatal("supR3HardenedWinGetRealDllSymbol: Unknown DLL %s (proc: %s)\n", pszDll, pszProcedure);
+    return NULL;
 }
 
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
index 93f034e..b19a9bc 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedNoCrt-win.cpp
@@ -38,9 +38,11 @@
 #include <VBox/err.h>
 #include <iprt/assert.h>
 #include <iprt/ctype.h>
+#include <iprt/heap.h>
 #include <iprt/string.h>
 #include <iprt/initterm.h>
 #include <iprt/param.h>
+#include <iprt/path.h>
 #include <iprt/mem.h>
 
 #include "SUPLibInternal.h"
@@ -96,6 +98,153 @@ RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
  * Memory allocator.
  */
 
+/** The handle of the heap we're using. */
+static HANDLE       g_hSupR3HardenedHeap = NULL;
+/** Number of heaps used during early process init. */
+static uint32_t     g_cSupR3HardenedEarlyHeaps = 0;
+/** Early process init heaps. */
+static struct
+{
+    /** The heap handle. */
+    RTHEAPSIMPLE    hHeap;
+    /** The heap block pointer. */
+    void           *pvBlock;
+    /** The size of the heap block. */
+    size_t          cbBlock;
+    /** Number of active allocations on this heap. */
+    size_t          cAllocations;
+} g_aSupR3HardenedEarlyHeaps[8];
+
+
+static uint32_t supR3HardenedEarlyFind(void *pv)
+{
+    uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
+    while (iHeap-- > 0)
+        if ((uintptr_t)pv - (uintptr_t)g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock < g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock)
+            return iHeap;
+    return UINT32_MAX;
+}
+
+
+static void supR3HardenedEarlyCompact(void)
+{
+    uint32_t iHeap = g_cSupR3HardenedEarlyHeaps;
+    while (iHeap-- > 0)
+        if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations == 0)
+        {
+            PVOID  pvMem = g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock;
+            SIZE_T cbMem = g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock;
+            if (iHeap + 1 < g_cSupR3HardenedEarlyHeaps)
+                g_aSupR3HardenedEarlyHeaps[iHeap] = g_aSupR3HardenedEarlyHeaps[g_cSupR3HardenedEarlyHeaps - 1];
+            g_cSupR3HardenedEarlyHeaps--;
+
+            NTSTATUS rcNt = NtFreeVirtualMemory(NtCurrentProcess(), &pvMem, &cbMem, MEM_RELEASE);
+            Assert(NT_SUCCESS(rcNt));
+            SUP_DPRINTF(("supR3HardenedEarlyCompact: Removed heap %#u (%#p LB %#zx)\n", iHeap, pvMem, cbMem));
+        }
+}
+
+
+static void *supR3HardenedEarlyAlloc(size_t cb, bool fZero)
+{
+    /*
+     * Try allocate on existing heaps.
+     */
+    void    *pv;
+    uint32_t iHeap = 0;
+    while (iHeap < g_cSupR3HardenedEarlyHeaps)
+    {
+        if (fZero)
+            pv = RTHeapSimpleAllocZ(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
+        else
+            pv = RTHeapSimpleAlloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, cb, 0);
+        if (pv)
+        {
+            g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations++;
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+            SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
+#endif
+            return pv;
+        }
+        iHeap++;
+    }
+
+    /*
+     * Add another heap.
+     */
+    if (iHeap == RT_ELEMENTS(g_aSupR3HardenedEarlyHeaps))
+        supR3HardenedFatal("Early heap table is full (cb=%#zx).\n", cb);
+    SIZE_T cbBlock = iHeap == 0 ? _1M : g_aSupR3HardenedEarlyHeaps[iHeap - 1].cbBlock * 2;
+    while (cbBlock <= cb * 2)
+        cbBlock *= 2;
+
+    PVOID pvBlock = NULL;
+    NTSTATUS rcNt = NtAllocateVirtualMemory(NtCurrentProcess(), &pvBlock, 0 /*ZeroBits*/, &cbBlock, MEM_COMMIT, PAGE_READWRITE);
+    if (!NT_SUCCESS(rcNt))
+        supR3HardenedFatal("NtAllocateVirtualMemory(,,,%#zx,,) failed: rcNt=%#x\n", cbBlock, rcNt);
+    SUP_DPRINTF(("New simple heap: #%u %p LB %#zx (for %zu allocation)\n", iHeap, pvBlock, cbBlock, cb));
+
+    RTHEAPSIMPLE hHeap;
+    int rc = RTHeapSimpleInit(&hHeap, pvBlock, cbBlock);
+    if (RT_FAILURE(rc))
+        supR3HardenedFatal("RTHeapSimpleInit(,%p,%#zx) failed: rc=%#x\n", pvBlock, cbBlock, rc);
+
+    if (fZero)
+        pv = RTHeapSimpleAllocZ(hHeap, cb, 0);
+    else
+        pv = RTHeapSimpleAlloc(hHeap, cb, 0);
+    if (!pv)
+        supR3HardenedFatal("RTHeapSimpleAlloc[Z] failed allocating %#zx bytes on a %#zu heap.\n", cb, cbBlock);
+
+    g_aSupR3HardenedEarlyHeaps[iHeap].pvBlock      = pvBlock;
+    g_aSupR3HardenedEarlyHeaps[iHeap].cbBlock      = cbBlock;
+    g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations = 1;
+    g_aSupR3HardenedEarlyHeaps[iHeap].hHeap        = hHeap;
+
+    Assert(g_cSupR3HardenedEarlyHeaps == iHeap);
+    g_cSupR3HardenedEarlyHeaps                     = iHeap + 1;
+
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+    SUP_DPRINTF(("Early heap: %p LB %#zx - alloc\n", pv, cb));
+#endif
+    return pv;
+}
+
+
+/**
+ * Lazy heap initialization function.
+ *
+ * @returns Heap handle.
+ */
+static HANDLE supR3HardenedHeapInit(void)
+{
+    Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED);
+    HANDLE hHeap = RtlCreateHeap(HEAP_GROWABLE | HEAP_CLASS_PRIVATE, NULL /*HeapBase*/,
+                                 0 /*ReserveSize*/, 0 /*CommitSize*/,  NULL /*Lock*/, NULL /*Parameters*/);
+    if (hHeap)
+    {
+        g_hSupR3HardenedHeap = hHeap;
+        return hHeap;
+    }
+
+    supR3HardenedFatal("RtlCreateHeap failed.\n");
+    return NULL;
+}
+
+
+/**
+ * Compacts the heaps before enter wait for parent/child.
+ */
+DECLHIDDEN(void) supR3HardenedWinCompactHeaps(void)
+{
+    if (g_hSupR3HardenedHeap)
+        RtlCompactHeap(g_hSupR3HardenedHeap, 0 /*dwFlags*/);
+    RtlCompactHeap(GetProcessHeap(), 0 /*dwFlags*/);
+    supR3HardenedEarlyCompact();
+}
+
+
+
 RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
 {
     return RTMemAllocTag(cb, pszTag);
@@ -116,13 +265,37 @@ RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW
 
 RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
 {
-    return suplibHardenedAllocZ(cb);
+    HANDLE hHeap = g_hSupR3HardenedHeap;
+    if (!hHeap)
+    {
+        if (   g_fSupEarlyProcessInit
+            && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
+            return supR3HardenedEarlyAlloc(cb, false /*fZero*/);
+        hHeap = supR3HardenedHeapInit();
+    }
+
+    void *pv = RtlAllocateHeap(hHeap, 0 /*fFlags*/, cb);
+    if (!pv)
+        supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
+    return pv;
 }
 
 
 RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
 {
-    return suplibHardenedAllocZ(cb);
+    HANDLE hHeap = g_hSupR3HardenedHeap;
+    if (!hHeap)
+    {
+        if (   g_fSupEarlyProcessInit
+            && g_enmSupR3HardenedMainState <= SUPR3HARDENEDMAINSTATE_WIN_EP_CALLED)
+            return supR3HardenedEarlyAlloc(cb, true /*fZero*/);
+        hHeap = supR3HardenedHeapInit();
+    }
+
+    void *pv = RtlAllocateHeap(hHeap, HEAP_ZERO_MEMORY, cb);
+    if (!pv)
+        supR3HardenedFatal("RtlAllocateHeap failed to allocate %zu bytes.\n", cb);
+    return pv;
 }
 
 
@@ -150,13 +323,92 @@ RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag) RT_NO_T
 
 RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW
 {
-    return suplibHardenedReAlloc(pvOld, cbNew);
+    if (!pvOld)
+        return RTMemAllocZTag(cbNew, pszTag);
+
+    void *pv;
+    if (g_fSupEarlyProcessInit)
+    {
+        uint32_t iHeap = supR3HardenedEarlyFind(pvOld);
+        if (iHeap != UINT32_MAX)
+        {
+#if 0 /* RTHeapSimpleRealloc is not implemented */
+            /* If this is before we can use a regular heap, we try resize
+               within the simple heap.  (There are a lot of array growing in
+               the ASN.1 code.) */
+            if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+            {
+                pv = RTHeapSimpleRealloc(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld, cbNew, 0);
+                if (pv)
+                {
+# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+                    SUP_DPRINTF(("Early heap: %p LB %#zx, was %p - realloc\n", pvNew, cbNew, pvOld));
+# endif
+                    return pv;
+                }
+            }
+#endif
+
+            /* Either we can't reallocate it on the same simple heap, or we're
+               past hardened main and wish to migrate everything over on the
+               real heap. */
+            size_t cbOld = RTHeapSimpleSize(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
+            pv = RTMemAllocTag(cbNew, pszTag);
+            if (pv)
+            {
+                memcpy(pv, pvOld, RT_MIN(cbOld, cbNew));
+                RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pvOld);
+                if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
+                    g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
+                if (   !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
+                    && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+                    supR3HardenedEarlyCompact();
+            }
+# ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+            SUP_DPRINTF(("Early heap: %p LB %#zx, was %p %LB %#zx - realloc\n", pv, cbNew, pvOld, cbOld));
+# endif
+            return pv;
+        }
+        Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
+    }
+
+    /* Allocate from the regular heap. */
+    HANDLE hHeap = g_hSupR3HardenedHeap;
+    Assert(hHeap != NULL);
+    pv = RtlReAllocateHeap(hHeap, 0 /*dwFlags*/, pvOld, cbNew);
+    if (!pv)
+        supR3HardenedFatal("RtlReAllocateHeap failed to allocate %zu bytes.\n", cbNew);
+    return pv;
 }
 
 
 RTDECL(void) RTMemFree(void *pv) RT_NO_THROW
 {
-    suplibHardenedFree(pv);
+    if (pv)
+    {
+        if (g_fSupEarlyProcessInit)
+        {
+            uint32_t iHeap = supR3HardenedEarlyFind(pv);
+            if (iHeap != UINT32_MAX)
+            {
+#ifdef SUPR3HARDENED_EARLY_HEAP_TRACE
+                SUP_DPRINTF(("Early heap: %p - free\n", pv));
+#endif
+                RTHeapSimpleFree(g_aSupR3HardenedEarlyHeaps[iHeap].hHeap, pv);
+                if (g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations)
+                    g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations--;
+                if (   !g_aSupR3HardenedEarlyHeaps[iHeap].cAllocations
+                    && g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+                    supR3HardenedEarlyCompact();
+                return;
+            }
+            Assert(g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED);
+        }
+
+        HANDLE hHeap = g_hSupR3HardenedHeap;
+        Assert(hHeap != NULL);
+        RtlFreeHeap(hHeap, 0 /* dwFlags*/, pv);
+    }
 }
 
 
@@ -189,3 +441,37 @@ RTDECL(void) RTMemWipeThoroughly(void *pv, size_t cb, size_t cMinPasses) RT_NO_T
     ASMMemoryFence();
 }
 
+
+
+/*
+ * path-win.cpp
+ */
+
+RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cbPath)
+{
+    int rc;
+    if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
+/** @todo Rainy day: improve this by checking the process parameter block
+ *        (needs to be normalized). */
+        rc = RTStrCopy(pszPath, cbPath, "C:\\");
+    else
+    {
+        /*
+         * GetCurrentDirectory may in some cases omit the drive letter, according
+         * to MSDN, thus the GetFullPathName call.
+         */
+        RTUTF16 wszCurPath[RTPATH_MAX];
+        if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath))
+        {
+            RTUTF16 wszFullPath[RTPATH_MAX];
+            if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL))
+                rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
+            else
+                rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
+        }
+        else
+            rc = RTErrConvertFromWin32(RtlGetLastWin32Error());
+    }
+    return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
index cafe8ea..4768aff 100644
--- a/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/VBoxSupLib-win.cpp
@@ -51,7 +51,7 @@ BOOL __stdcall DllMainEntrypoint(HANDLE hModule, DWORD dwReason, PVOID pvReserve
             WCHAR wszName[RTPATH_MAX];
             SetLastError(NO_ERROR);
             if (   GetModuleFileNameW((HMODULE)hModule, wszName, RT_ELEMENTS(wszName)) > 0
-                && GetLastError() == NO_ERROR)
+                && RtlGetLastWin32Error() == NO_ERROR)
             {
                 int cExtraLoads = 2;
                 while (cExtraLoads-- > 0)
diff --git a/src/VBox/HostDrivers/Support/win/import-template-kernel32.h b/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
index 331a780..1466d94 100644
--- a/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
+++ b/src/VBox/HostDrivers/Support/win/import-template-kernel32.h
@@ -1,10 +1,9 @@
-SUPHARNT_IMPORT_STDCALL(CloseHandle, 4)
 SUPHARNT_IMPORT_STDCALL(CreateFileW, 28)
 SUPHARNT_IMPORT_STDCALL(CreateProcessW, 40)
 SUPHARNT_IMPORT_STDCALL(ExitProcess, 4)
-SUPHARNT_IMPORT_STDCALL(GetCurrentThreadId, 0)
 SUPHARNT_IMPORT_STDCALL(GetFullPathNameA, 16)
-SUPHARNT_IMPORT_STDCALL(GetLastError, 0)
+SUPHARNT_IMPORT_STDCALL(GetFullPathNameW, 16)
+SUPHARNT_IMPORT_STDCALL(GetCurrentDirectoryW, 8)
 SUPHARNT_IMPORT_STDCALL(GetModuleFileNameW, 12)
 SUPHARNT_IMPORT_STDCALL(GetModuleHandleA, 4)
 SUPHARNT_IMPORT_STDCALL(GetModuleHandleW, 4)
@@ -12,17 +11,10 @@ SUPHARNT_IMPORT_STDCALL(GetProcAddress, 8)
 SUPHARNT_IMPORT_STDCALL(GetProcessHeap, 0)
 SUPHARNT_IMPORT_STDCALL(GetSystemDirectoryW, 8)
 SUPHARNT_IMPORT_STDCALL(GetTickCount, 0)
-SUPHARNT_IMPORT_STDCALL(HeapAlloc, 12)
-SUPHARNT_IMPORT_STDCALL(HeapCompact, 8)
-SUPHARNT_IMPORT_STDCALL(HeapFree, 8)
-SUPHARNT_IMPORT_STDCALL(HeapReAlloc, 16)
 SUPHARNT_IMPORT_STDCALL(LoadLibraryExW, 12)
 SUPHARNT_IMPORT_STDCALL(OutputDebugStringA, 4)
-SUPHARNT_IMPORT_STDCALL(SetLastError, 4)
-SUPHARNT_IMPORT_STDCALL(Sleep, 4)
 SUPHARNT_IMPORT_STDCALL(TlsAlloc, 0)
 SUPHARNT_IMPORT_STDCALL(TlsGetValue, 4)
 SUPHARNT_IMPORT_STDCALL(TlsSetValue, 8)
-SUPHARNT_IMPORT_STDCALL(VirtualProtectEx, 20)
 SUPHARNT_IMPORT_STDCALL(WriteFile, 20)
 
diff --git a/src/VBox/HostDrivers/Support/win/import-template-ntdll.h b/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
index 1f7b917..a9318c4 100644
--- a/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
+++ b/src/VBox/HostDrivers/Support/win/import-template-ntdll.h
@@ -1,6 +1,9 @@
 SUPHARNT_IMPORT_SYSCALL(NtAllocateVirtualMemory, 24)
+SUPHARNT_IMPORT_SYSCALL(NtClearEvent, 4)
 SUPHARNT_IMPORT_SYSCALL(NtClose, 4)
+SUPHARNT_IMPORT_SYSCALL(NtCreateEvent, 20)
 SUPHARNT_IMPORT_SYSCALL(NtCreateFile, 44)
+SUPHARNT_IMPORT_SYSCALL(NtCreateSymbolicLinkObject, 16)
 SUPHARNT_IMPORT_SYSCALL(NtDelayExecution, 8)
 SUPHARNT_IMPORT_SYSCALL(NtDeviceIoControlFile, 40)
 SUPHARNT_IMPORT_SYSCALL(NtDuplicateObject, 28)
@@ -8,28 +11,35 @@ SUPHARNT_IMPORT_SYSCALL(NtFreeVirtualMemory, 16)
 SUPHARNT_IMPORT_SYSCALL(NtGetContextThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtMapViewOfSection, 40)
 SUPHARNT_IMPORT_SYSCALL(NtOpenDirectoryObject, 12)
+SUPHARNT_IMPORT_SYSCALL(NtOpenEvent, 12)
 SUPHARNT_IMPORT_SYSCALL(NtOpenKey, 12)
 SUPHARNT_IMPORT_SYSCALL(NtOpenProcess, 16)
 SUPHARNT_IMPORT_SYSCALL(NtOpenProcessToken, 12)
+SUPHARNT_IMPORT_SYSCALL(NtOpenSymbolicLinkObject, 12)
 SUPHARNT_IMPORT_SYSCALL(NtOpenThread, 16)
 SUPHARNT_IMPORT_SYSCALL(NtOpenThreadToken, 16)
 SUPHARNT_IMPORT_SYSCALL(NtProtectVirtualMemory, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryFile, 44)
 SUPHARNT_IMPORT_SYSCALL(NtQueryDirectoryObject, 28)
+SUPHARNT_IMPORT_SYSCALL(NtQueryEvent, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationFile, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationProcess, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationThread, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryInformationToken, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQueryObject, 20)
 SUPHARNT_IMPORT_SYSCALL(NtQuerySecurityObject, 20)
+SUPHARNT_IMPORT_SYSCALL(NtQuerySymbolicLinkObject, 12)
+SUPHARNT_IMPORT_SYSCALL(NtQuerySystemInformation, 16)
 SUPHARNT_IMPORT_SYSCALL(NtQueryTimerResolution, 12)
 SUPHARNT_IMPORT_SYSCALL(NtQueryValueKey, 24)
 SUPHARNT_IMPORT_SYSCALL(NtQueryVirtualMemory, 24)
 SUPHARNT_IMPORT_SYSCALL(NtReadFile, 36)
 SUPHARNT_IMPORT_SYSCALL(NtReadVirtualMemory, 20)
+SUPHARNT_IMPORT_SYSCALL(NtResetEvent, 8)
 SUPHARNT_IMPORT_SYSCALL(NtResumeProcess, 4)
 SUPHARNT_IMPORT_SYSCALL(NtResumeThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtSetContextThread, 8)
+SUPHARNT_IMPORT_SYSCALL(NtSetEvent, 8)
 SUPHARNT_IMPORT_SYSCALL(NtSetInformationFile, 20)
 SUPHARNT_IMPORT_SYSCALL(NtSetInformationObject, 16)
 SUPHARNT_IMPORT_SYSCALL(NtSetInformationProcess, 16)
@@ -40,32 +50,46 @@ SUPHARNT_IMPORT_SYSCALL(NtSuspendThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtTerminateProcess, 8)
 SUPHARNT_IMPORT_SYSCALL(NtTerminateThread, 8)
 SUPHARNT_IMPORT_SYSCALL(NtUnmapViewOfSection, 8)
-SUPHARNT_IMPORT_SYSCALL(NtWaitForSingleObject, 12)
 SUPHARNT_IMPORT_SYSCALL(NtWaitForMultipleObjects, 20)
+SUPHARNT_IMPORT_SYSCALL(NtWaitForSingleObject, 12)
 SUPHARNT_IMPORT_SYSCALL(NtWriteFile, 36)
 SUPHARNT_IMPORT_SYSCALL(NtWriteVirtualMemory, 20)
 SUPHARNT_IMPORT_SYSCALL(NtYieldExecution, 0)
+SUPHARNT_IMPORT_SYSCALL(NtCreateSection, 28)
+SUPHARNT_IMPORT_SYSCALL(NtQueryVolumeInformationFile, 20)
 
+SUPHARNT_IMPORT_STDCALL_EARLY(LdrInitializeThunk, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(LdrRegisterDllNotification, 16)
 
-SUPHARNT_IMPORT_STDCALL(NtCreateSection, 28)
-SUPHARNT_IMPORT_STDCALL(NtQueryVolumeInformationFile, 20)
-SUPHARNT_IMPORT_STDCALL(LdrInitializeThunk, 12)
 SUPHARNT_IMPORT_STDCALL(RtlAddAccessAllowedAce, 16)
 SUPHARNT_IMPORT_STDCALL(RtlAddAccessDeniedAce, 16)
+SUPHARNT_IMPORT_STDCALL(RtlAllocateHeap, 12)
+SUPHARNT_IMPORT_STDCALL(RtlCompactHeap, 8)
 SUPHARNT_IMPORT_STDCALL(RtlCopySid, 12)
 SUPHARNT_IMPORT_STDCALL(RtlCreateAcl, 12)
+SUPHARNT_IMPORT_STDCALL(RtlCreateHeap, 24)
 SUPHARNT_IMPORT_STDCALL(RtlCreateProcessParameters, 40)
 SUPHARNT_IMPORT_STDCALL(RtlCreateSecurityDescriptor, 8)
 SUPHARNT_IMPORT_STDCALL(RtlCreateUserProcess, 40)
 SUPHARNT_IMPORT_STDCALL(RtlCreateUserThread, 40)
 SUPHARNT_IMPORT_STDCALL(RtlDestroyProcessParameters, 4)
-SUPHARNT_IMPORT_STDCALL(RtlDosApplyFileIsolationRedirection_Ustr, 36)
-SUPHARNT_IMPORT_STDCALL(RtlEqualSid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlDosApplyFileIsolationRedirection_Ustr, 36)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlEqualSid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY_OPTIONAL(RtlExitUserProcess, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlExitUserThread, 4)
 SUPHARNT_IMPORT_STDCALL(RtlExpandEnvironmentStrings_U, 16)
-SUPHARNT_IMPORT_STDCALL(RtlFreeUnicodeString, 4)
-SUPHARNT_IMPORT_STDCALL(RtlGetVersion, 4)
-SUPHARNT_IMPORT_STDCALL(RtlInitializeSid, 12)
-SUPHARNT_IMPORT_STDCALL(RtlNtStatusToDosError, 4)
+SUPHARNT_IMPORT_STDCALL(RtlFreeHeap, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlFreeUnicodeString, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetLastNtStatus, 0)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetLastWin32Error, 0)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlGetVersion, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlInitializeSid, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlNtStatusToDosError, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlReAllocateHeap, 16)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlRestoreLastWin32Error, 4)
 SUPHARNT_IMPORT_STDCALL(RtlSetDaclSecurityDescriptor, 16)
-SUPHARNT_IMPORT_STDCALL(RtlSubAuthoritySid, 8)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSetLastWin32Error, 4)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSetLastWin32ErrorAndNtStatusFromNtStatus, 4)
+SUPHARNT_IMPORT_STDCALL(RtlSizeHeap, 12)
+SUPHARNT_IMPORT_STDCALL_EARLY(RtlSubAuthoritySid, 8)
 
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
index 93a99d6..c8f2e5f 100644
--- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
@@ -89,7 +89,7 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedShaders(GLuint program,
         GLsizei i;
         GLuint *ids=(GLuint*)&pLocal[1];
 
-        for (i=0; i<*pLocal; ++i);
+        for (i=0; i<*pLocal; ++i)
           ids[i] = crStateGLSLShaderHWIDtoID(ids[i]);
     }
 
diff --git a/src/VBox/Installer/win/Makefile.kmk b/src/VBox/Installer/win/Makefile.kmk
index c856af6..c731135 100644
--- a/src/VBox/Installer/win/Makefile.kmk
+++ b/src/VBox/Installer/win/Makefile.kmk
@@ -49,23 +49,9 @@ include $(PATH_SUB_CURRENT)/Resources/Makefile.kmk
 # Globals and targets.
 # Note: en_US *must* come first for the dependency file generation.
 #
-VBOX_INSTALLER_LANGUAGES  = en_US de_DE fr_FR it_IT zh_TW
-VBOX_INSTALLER_LANGUAGES += $(VBOX_INSTALLER_ADD_LANGUAGES)
-
-#
-# Use merge modules if we're not doing an official release.
-# This will increase the overall installer size significantly because
-# merge modules are not able to use a common .cab file to reduce their
-# size.
-#
-ifneq ($(int-mod $(VBOX_VERSION_BUILD),2),0)
- VBOX_WITH_MSM_INSTALL := 1
- VBOX_INSTALLER_LANGUAGES = en_US
-endif
-
-ifeq ($(USERNAME),andy)
- VBOX_WITH_MSM_INSTALL := 1
- VBOX_INSTALLER_LANGUAGES = en_US
+ifndef VBOX_INSTALLER_LANGUAGES
+ VBOX_INSTALLER_LANGUAGES  = en_US de_DE fr_FR it_IT zh_TW
+ VBOX_INSTALLER_LANGUAGES += $(VBOX_INSTALLER_ADD_LANGUAGES)
 endif
 
 #
@@ -77,19 +63,32 @@ ifeq ($(KBUILD_TARGET_ARCH),amd64)
 endif
 
 # We only ship the merge modules in locale en_US for the moment.
-VBOX_INSTALLER_MERGE_LANGUAGES = $(VBOX_INSTALLER_LANGUAGES)
+ifdef VBOX_WITH_MSM_INSTALL
+ VBOX_INSTALLER_LANGUAGES := en_US
+ VBOX_INSTALLER_MERGE_LANGUAGES = $(VBOX_INSTALLER_LANGUAGES)
+endif
 
 #
 # We don't have the license text in another language than English yet,
 # so just define the branding targets to use the English one for now.
+# The installer generation assumes that there is a translation for each
+# of VBOX_INSTALLER_LANGUAGES.
 #
 $(foreach lang,$(VBOX_INSTALLER_LANGUAGES), \
-	$(eval VBOX_BRAND_$(lang)_LICENSE_RTF := $(VBOX_BRAND_LICENSE_RTF)) \
+	$(eval VBOX_BRAND_$(lang)_LICENSE_RTF := $(VBOX_BRAND_LICENSE_RTF)))
+
+# Set the codepage for all languages to 1252, covers most cases.
+$(foreach lang,$(sort $(VBOX_INSTALLER_LANGUAGES) $(VBOX_LICENSE_ADD_LANGUAGES) $(VBOX_MANUAL_ADD_LANGUAGES)), \
 	$(eval VBOX_BRAND_$(lang)_LANGUAGE_CODEPAGE := 1252))
 
 # Some languages need another codepage than 1252. Override them here.
 VBOX_BRAND_zh_TW_LANGUAGE_CODEPAGE := 950
 
+# Standard language names (in the native language), to be extended as we go.
+# VBOX_BRAND_$(lang)_LANG_NAME must be defined for each language which occurs
+# in either # VBOX_LICENSE_ADD_LANGUAGES or VBOX_MANUAL_ADD_LANGUAGES.
+VBOX_BRAND_fr_FR_LANG_NAME := Français
+
 VBOX_PATH_WIN_INST_SRC := $(PATH_SUB_CURRENT)
 VBOX_WIN_INST_OUT_DIR := $(PATH_TARGET)/Installer/win
 
@@ -300,7 +299,7 @@ $(VBOX_WIN_INST_OUT_DIR)/Files_License.wxi: $(MAKEFILE_CURRENT) | $$(dir $$@)
 	$(APPEND) $@ '<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">'
 	$(APPEND) $@ '	<File Id="file_License_en_US.rtf" Name="License_en_US.rtf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(VBOX_BRAND_LICENSE_RTF)">' \
 	             '	</File>'
-	$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
+	$(APPEND) -n $@ $(foreach lang,$(VBOX_LICENSE_ADD_LANGUAGES), \
 	             '	<File Id="file_License_$(lang).rtf" Name="License_$(lang).rtf" DiskId="$(VBOX_INSTALLER_COMMON_DISKID)" Vital="yes" Source="$(VBOX_BRAND_$(lang)_LICENSE_RTF)">' \
 	             '	</File>')
 	$(APPEND) $@ '</Include>'
@@ -316,22 +315,22 @@ ifdef VBOX_WITH_DOCS_PACKING
 	$(APPEND) $@ '	<Shortcut Id="sc_StartMenu_ManualCHM_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (CHM, English)" Description="!(loc.StartMenu_UserManual)"' \
 	             '            Target="[INSTALLDIR]\VirtualBox.chm" WorkingDirectory="dir_Documents" Advertise="no"/>'
 	$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
-	             '	<Shortcut Id="sc_StartMenu_ManualCHM_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_UserManual) (CHM, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
-		     '            Description="$!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\VirtualBox_$(lang).chm" WorkingDirectory="dir_Documents"/>')
+	             '	<Shortcut Id="sc_StartMenu_ManualCHM_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (CHM, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+		     '            Description="!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\VirtualBox_$(lang).chm" WorkingDirectory="dir_Documents"/>')
 endif
 	$(APPEND) $@ '	<Shortcut Id="sc_StartMenu_ManualPDF_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (PDF, English)" Description="!(loc.StartMenu_UserManual)"' \
 	             '            Target="[INSTALLDIR]\doc\UserManual.pdf" WorkingDirectory="dir_Documents" Advertise="no"/>'
 	$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
-	             '	<Shortcut Id="sc_StartMenu_ManualPDF_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_UserManual) (PDF, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
-		     '            Description="$!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\doc\UserManual_$(lang).pdf" WorkingDirectory="dir_Documents"/>')
+	             '	<Shortcut Id="sc_StartMenu_ManualPDF_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_UserManual) (PDF, $(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+		     '            Description="!(loc.StartMenu_UserManual) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="[INSTALLDIR]\doc\UserManual_$(lang).pdf" WorkingDirectory="dir_Documents"/>')
 	#
 	# License(s) (RTF)
 	#
 	$(APPEND) $@ '	<Shortcut Id="sc_StartMenu_License_en_US" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_License) (English)" Description="!(loc.StartMenu_License)"' \
 	             '            Target="[INSTALLDIR]License_en_US.rtf" WorkingDirectory="INSTALLDIR" Advertise="no"/>'
-	$(APPEND) -n $@ $(foreach lang,$(VBOX_MANUAL_ADD_LANGUAGES), \
-	             '	<Shortcut Id="sc_StartMenu_License_$(lang)" Directory="dir_StartMenuVBox" Name="$!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))"' \
-		     '            Description="$!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="License_$(lang).rtf" WorkingDirectory="INSTALLDIR"/>')
+	$(APPEND) -n $@ $(foreach lang,$(VBOX_LICENSE_ADD_LANGUAGES), \
+	             '	<Shortcut Id="sc_StartMenu_License_$(lang)" Directory="dir_StartMenuVBox" Name="!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))"' \
+		     '            Description="!(loc.StartMenu_License) ($(VBOX_BRAND_$(lang)_LANG_NAME))" Target="License_$(lang).rtf" WorkingDirectory="INSTALLDIR"/>')
 	$(APPEND) $@ '</Include>'
 
 #
diff --git a/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi b/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
index 58ee600..c9a11db 100644
--- a/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
+++ b/src/VBox/Installer/win/VBoxMergeNetFltSeq.wxi
@@ -19,28 +19,28 @@
 <?if $(env.VBOX_WITH_NETFLT) = "yes" ?>
     <Custom Action="ca_RollbackInstallNetFltArgs" Before="ca_RollbackInstallNetFlt" >
         <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
-            <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+            <![CDATA[NOT Installed]]>
         <?else ?>
             <![CDATA[&VBoxNetworkFlt=3]]>
         <?endif ?>
     </Custom>
     <Custom Action="ca_RollbackInstallNetFlt" Before="ca_InstallNetFlt" >
         <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
-            <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+            <![CDATA[NOT Installed]]>
         <?else ?>
             <![CDATA[&VBoxNetworkFlt=3]]>
         <?endif ?>
     </Custom>
     <Custom Action="ca_InstallNetFltArgs" Before="ca_InstallNetFlt" >
         <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
-            <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+            <![CDATA[NOT Installed]]>
         <?else ?>
             <![CDATA[&VBoxNetworkFlt=3]]>
         <?endif ?>
     </Custom>
     <Custom Action="ca_InstallNetFlt" Before="InstallFinalize" >
         <?if $(env.VBOX_WITH_MSM_INSTALL) = "yes" ?>
-            <![CDATA[UPGRADINGPRODUCTCODE OR (NOT Installed)]]>
+            <![CDATA[NOT Installed]]>
         <?else ?>
             <![CDATA[&VBoxNetworkFlt=3]]>
         <?endif ?>
diff --git a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
index 3a5e698..73db613 100644
--- a/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
+++ b/src/VBox/Main/cbinding/LegacyVBoxXPCOMCGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 91907 $ */
+/* $Revision: 96259 $ */
 /** @file VBoxXPCOMCGlue.c
  * Glue code for dynamically linking to VBoxCAPI, LEGACY VARIANT.
  */
@@ -266,7 +266,7 @@ int VBoxCGlueInit(void)
     if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0)
         return 0;
 #elif defined(__APPLE__)
-    if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0)
+    if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0)
         return 0;
 #elif defined(__FreeBSD__)
     if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0)
diff --git a/src/VBox/Main/cbinding/VBoxCAPIGlue.c b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
index d229a6b..500cb38 100644
--- a/src/VBox/Main/cbinding/VBoxCAPIGlue.c
+++ b/src/VBox/Main/cbinding/VBoxCAPIGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 91907 $ */
+/* $Revision: 96259 $ */
 /** @file
  * Glue code for dynamically linking to VBoxCAPI.
  */
@@ -266,7 +266,7 @@ int VBoxCGlueInit(void)
     if (tryLoadLibrary("/opt/VirtualBox/i386", 1) == 0)
         return 0;
 #elif defined(__APPLE__)
-    if (tryLoadLibrary("/Application/VirtualBox.app/Contents/MacOS", 1) == 0)
+    if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", 1) == 0)
         return 0;
 #elif defined(__FreeBSD__)
     if (tryLoadLibrary("/usr/local/lib/virtualbox", 1) == 0)
diff --git a/src/VBox/Main/cbinding/capiidl.xsl b/src/VBox/Main/cbinding/capiidl.xsl
index 7c3635f..a450a19 100644
--- a/src/VBox/Main/cbinding/capiidl.xsl
+++ b/src/VBox/Main/cbinding/capiidl.xsl
@@ -197,6 +197,7 @@ typedef const BSTR CBSTR;
 
 #define ComSafeArrayAsInParam(f) (f)
 #define ComSafeArrayAsOutParam(f) (&(f))
+#define ComSafeArrayAsOutTypeParam(f,t) (&(f))
 #define ComSafeArrayAsOutIfaceParam(f,t) (&(f))
 
 #else /* !WIN32 */
@@ -867,6 +868,7 @@ typedef struct SAFEARRAY
 
 #define ComSafeArrayAsInParam(f) ((f)->c), ((f)->pv)
 #define ComSafeArrayAsOutParam(f) (&((f)->c)), (&((f)->pv))
+#define ComSafeArrayAsOutTypeParam(f,t) (&((f)->c)), (t**)(&((f)->pv))
 #define ComSafeArrayAsOutIfaceParam(f,t) (&((f)->c)), (t**)(&((f)->pv))
 
 /* Glossing over differences between COM and XPCOM */
@@ -2096,7 +2098,7 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
   <xsl:if test="not(@readonly='yes')">
     <!-- setter (COM compatible) -->
     <xsl:text>#define </xsl:text>
-    <xsl:value-of select="concat($iface, '_set_')"/>
+    <xsl:value-of select="concat($iface, '_put_')"/>
     <xsl:call-template name="capitalize">
       <xsl:with-param name="str" select="@name"/>
     </xsl:call-template>
@@ -2285,7 +2287,7 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
   <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,33,2)"/>
   <xsl:text>, 0x</xsl:text><xsl:value-of select="substring(@uuid,35,2)"/>
   <xsl:text> } \&#x0A;}&#x0A;</xsl:text>
-  <xsl:text>enum </xsl:text>
+  <xsl:text>typedef enum </xsl:text>
   <xsl:value-of select="@name"/>
   <xsl:text>&#x0A;{&#x0A;</xsl:text>
   <xsl:variable name="this" select="."/>
@@ -2299,7 +2301,9 @@ typedef PCVBOXCAPI (*PFNVBOXGETXPCOMCFUNCTIONS)(unsigned uVersion);
     </xsl:if>
     <xsl:text>&#x0A;</xsl:text>
   </xsl:for-each>
-  <xsl:text>};&#x0A;</xsl:text>
+  <xsl:text>} </xsl:text>
+  <xsl:value-of select="@name"/>
+  <xsl:text>;&#x0A;</xsl:text>
   <xsl:text>/* End of enum </xsl:text>
   <xsl:value-of select="@name"/>
   <xsl:text> declaration */
diff --git a/src/VBox/Main/cbinding/tstCAPIGlue.c b/src/VBox/Main/cbinding/tstCAPIGlue.c
index c05ec30..2396a09 100644
--- a/src/VBox/Main/cbinding/tstCAPIGlue.c
+++ b/src/VBox/Main/cbinding/tstCAPIGlue.c
@@ -1,4 +1,4 @@
-/* $Revision: 93190 $ */
+/* $Revision: 96185 $ */
 /** @file tstCAPIGlue.c
  * Demonstrator program to illustrate use of C bindings of Main API.
  *
@@ -748,7 +748,7 @@ static void startVM(const char *argv0, IVirtualBox *virtualBox, ISession *sessio
         return;
     }
 
-    rc = IMachine_get_Groups(machine, ComSafeArrayAsOutParam(groupsSA));
+    rc = IMachine_get_Groups(machine, ComSafeArrayAsOutTypeParam(groupsSA, BSTR));
     if (SUCCEEDED(rc))
     {
         BSTR *groups = NULL;
diff --git a/src/VBox/Main/include/ConsoleEvents.h b/src/VBox/Main/include/ConsoleEvents.h
deleted file mode 100644
index a4718ac..0000000
--- a/src/VBox/Main/include/ConsoleEvents.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/** @file
- *
- * VirtualBox console event handling
- */
-
-/*
- * Copyright (C) 2006-2010 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.
- */
-
-#ifndef ____H_CONSOLEEVENTS
-#define ____H_CONSOLEEVENTS
-
-#include <iprt/semaphore.h>
-
-template<class C> class ConsoleEventBuffer
-{
-public:
-   /**
-    * Constructor
-    *
-    * @param size FIFO size in elements.
-    */
-    ConsoleEventBuffer(size_t size) :
-        sz(size), buf(new C[size]), curg(0), curp(0), full(false)
-    {
-        RTSemMutexCreate(&mutex);
-    }
-
-    /**
-     * Destructor
-     *
-     */
-    virtual ~ConsoleEventBuffer()
-    {
-        RTSemMutexDestroy(mutex);
-        delete buf;
-    }
-
-    /**
-     *  Opens the buffer for extraction of elements. Must be called before #get().
-     */
-    void open()
-    {
-        lock();
-    }
-
-    /**
-     *  Closes the buffer previously opened by #open(). Must be called after #get().
-     */
-    void close()
-    {
-        unlock();
-    }
-
-    /**
-     *  Gets the element from the buffer. Requires #open() before and #close()
-     *  after. Returns the first element and removes it from the buffer. If
-     *  the buffer is empty, returns an empty element (constructed with the
-     *  default constructor).
-     */
-    C get()
-    {
-        C c;
-        if (full || curg != curp)
-        {
-            c = buf[curg];
-            ++curg %= sz;
-            full = false;
-        }
-        return c;
-    }
-
-    /**
-     *  Puts the element to the end of the buffer. #open()/#close() must not
-     *  be used. Returns 1 if successful, or 0 if the buffer is full, or 2
-     *  if the element is invalid.
-     */
-    size_t put(C c)
-    {
-        if (!c.isValid())
-            return 2; // invalid element
-        lock();
-        size_t i = 0;
-        if (!full)
-        {
-            buf[curp] = c;
-            ++curp %= sz;
-            i++;
-            full = curg == curp;
-        }
-        unlock();
-        return i;
-    }
-
-    /**
-     *  Puts the number of elements to the buffer. #open()/#close() must not
-     *  be used. Returns the count of elements placed. If it is less than
-     *  the count passed as an argument then the buffer is full. If it is
-     *  greater (special case) then the invalid element is encountered and
-     *  its index is return value munis count minus 1.
-     */
-    size_t put(C *codes, size_t count)
-    {
-        lock();
-        size_t i = 0;
-        while (i < count && !full)
-        {
-            if (!codes[i].isValid())
-            {
-                i += count + 1; // invalid code
-                break;
-            }
-            buf[curp] = codes[i++];
-            ++curp %= sz;
-            full = curg == curp;
-        }
-        unlock();
-        return i;
-    }
-
-private:
-    /**
-     * Acquire the local mutex
-     */
-    void lock()
-    {
-        RTSemMutexRequest(mutex, RT_INDEFINITE_WAIT);
-    }
-    /**
-     *  Release the local mutex
-     */
-    void unlock()
-    {
-        RTSemMutexRelease(mutex);
-    }
-
-private:
-    size_t sz;
-    C *buf;
-    size_t curg, curp;
-    bool full;
-    RTSEMMUTEX mutex;
-};
-
-#endif // ____H_CONSOLEEVENTS
-/* vi: set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/src/VBox/Main/include/KeyboardImpl.h b/src/VBox/Main/include/KeyboardImpl.h
index a94e67b..71cee23 100644
--- a/src/VBox/Main/include/KeyboardImpl.h
+++ b/src/VBox/Main/include/KeyboardImpl.h
@@ -19,7 +19,6 @@
 #define ____H_KEYBOARDIMPL
 
 #include "VirtualBoxBase.h"
-#include "ConsoleEvents.h"
 #include "EventImpl.h"
 
 #include <VBox/vmm/pdmdrv.h>
@@ -39,9 +38,6 @@ public:
     }
     int scan;
 };
-// template instantiation
-typedef ConsoleEventBuffer<KeyboardEvent> KeyboardEventBuffer;
-
 class Console;
 
 class ATL_NO_VTABLE Keyboard :
diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h
index bb91290..d3c6d85 100644
--- a/src/VBox/Main/include/MachineImpl.h
+++ b/src/VBox/Main/include/MachineImpl.h
@@ -1213,7 +1213,7 @@ private:
     HRESULT setMachineState(MachineState_T aMachineState);
     HRESULT updateMachineStateOnClient();
 
-    HRESULT mRemoveSavedState;
+    bool mRemoveSavedState;
 
     ConsoleTaskData mConsoleTaskData;
 
diff --git a/src/VBox/Main/include/MouseImpl.h b/src/VBox/Main/include/MouseImpl.h
index 404c759..21dde0e 100644
--- a/src/VBox/Main/include/MouseImpl.h
+++ b/src/VBox/Main/include/MouseImpl.h
@@ -19,7 +19,6 @@
 #define ____H_MOUSEIMPL
 
 #include "VirtualBoxBase.h"
-#include "ConsoleEvents.h"
 #include "ConsoleImpl.h"
 #include "EventImpl.h"
 #include <VBox/vmm/pdmdrv.h>
diff --git a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
index 1b0fb66..3c1e233 100644
--- a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
+++ b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
@@ -1268,6 +1268,11 @@ GuestWaitEventBase::GuestWaitEventBase(void)
 
 GuestWaitEventBase::~GuestWaitEventBase(void)
 {
+    if (mEventSem != NIL_RTSEMEVENT)
+    {
+        RTSemEventDestroy(mEventSem);
+        mEventSem = NIL_RTSEMEVENT;
+    }
 }
 
 int GuestWaitEventBase::Init(uint32_t uCID)
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp
index c8c5718..a814909 100644
--- a/src/VBox/Main/src-server/ApplianceImplExport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp
@@ -1057,21 +1057,17 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
     pelmVirtualSystem->setAttribute("ovf:id", strVMName);
 
     // product info
-    std::list<VirtualSystemDescriptionEntry*> llProduct = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
+    std::list<VirtualSystemDescriptionEntry*> llProduct    = vsdescThis->findByType(VirtualSystemDescriptionType_Product);
     std::list<VirtualSystemDescriptionEntry*> llProductUrl = vsdescThis->findByType(VirtualSystemDescriptionType_ProductUrl);
-    std::list<VirtualSystemDescriptionEntry*> llVendor = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
-    std::list<VirtualSystemDescriptionEntry*> llVendorUrl = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
-    std::list<VirtualSystemDescriptionEntry*> llVersion = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
-    bool fProduct = llProduct.size() && !llProduct.back()->strVBoxCurrent.isEmpty();
+    std::list<VirtualSystemDescriptionEntry*> llVendor     = vsdescThis->findByType(VirtualSystemDescriptionType_Vendor);
+    std::list<VirtualSystemDescriptionEntry*> llVendorUrl  = vsdescThis->findByType(VirtualSystemDescriptionType_VendorUrl);
+    std::list<VirtualSystemDescriptionEntry*> llVersion    = vsdescThis->findByType(VirtualSystemDescriptionType_Version);
+    bool fProduct    = llProduct.size()    && !llProduct.back()->strVBoxCurrent.isEmpty();
     bool fProductUrl = llProductUrl.size() && !llProductUrl.back()->strVBoxCurrent.isEmpty();
-    bool fVendor = llVendor.size() && !llVendor.back()->strVBoxCurrent.isEmpty();
-    bool fVendorUrl = llVendorUrl.size() && !llVendorUrl.back()->strVBoxCurrent.isEmpty();
-    bool fVersion = llVersion.size() && !llVersion.back()->strVBoxCurrent.isEmpty();
-    if (fProduct ||
-        fProductUrl ||
-        fVersion ||
-        fVendorUrl ||
-        fVersion)
+    bool fVendor     = llVendor.size()     && !llVendor.back()->strVBoxCurrent.isEmpty();
+    bool fVendorUrl  = llVendorUrl.size()  && !llVendorUrl.back()->strVBoxCurrent.isEmpty();
+    bool fVersion    = llVersion.size()    && !llVersion.back()->strVBoxCurrent.isEmpty();
+    if (fProduct || fProductUrl || fVendor || fVendorUrl || fVersion)
     {
         /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
             <Info>Meta-information about the installed software</Info>
diff --git a/src/VBox/Main/src-server/ApplianceImplImport.cpp b/src/VBox/Main/src-server/ApplianceImplImport.cpp
index 1eada73..6077aea 100644
--- a/src/VBox/Main/src-server/ApplianceImplImport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplImport.cpp
@@ -389,8 +389,9 @@ STDMETHODIMP Appliance::Interpret()
                 }
             }
             /* else we use the ovf configuration. */
-            else if (size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size() >  0)
+            else if (vsysThis.llEthernetAdapters.size() >  0)
             {
+                size_t cEthernetAdapters = vsysThis.llEthernetAdapters.size();
                 uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(ChipsetType_PIIX3);
 
                 /* Check for the constrains */
@@ -3820,10 +3821,8 @@ void Appliance::importMachines(ImportStack &stack,
     list< ComObjPtr<VirtualSystemDescription> >::const_iterator it1;
     /* Iterate through all virtual systems of that appliance */
     size_t i = 0;
-    for (it = reader.m_llVirtualSystems.begin(),
-         it1 = m->virtualSystemDescriptions.begin();
-         it != reader.m_llVirtualSystems.end(),
-         it1 != m->virtualSystemDescriptions.end();
+    for (it  = reader.m_llVirtualSystems.begin(), it1  = m->virtualSystemDescriptions.begin();
+         it != reader.m_llVirtualSystems.end() && it1 != m->virtualSystemDescriptions.end();
          ++it, ++it1, ++i)
     {
         const ovf::VirtualSystem &vsysThis = *it;
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index 3889a01..2eb2947 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (C) 2004-2013 Oracle Corporation
+ * Copyright (C) 2004-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -5346,7 +5346,10 @@ STDMETHODIMP Machine::SetExtraData(IN_BSTR aKey, IN_BSTR aValue)
                 // creates a new key if needed
 
         bool fNeedsGlobalSaveSettings = false;
-        saveSettings(&fNeedsGlobalSaveSettings);
+        // This saving of settings is tricky: there is no "old state" for the
+        // extradata items at all (unlike all other settings), so the old/new
+        // settings comparison would give a wrong result!
+        saveSettings(&fNeedsGlobalSaveSettings, SaveS_Force);
 
         if (fNeedsGlobalSaveSettings)
         {
@@ -5797,6 +5800,11 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task)
                                      logFolder.c_str(), RTPATH_DELIMITER, i);
                     RTFileDelete(log.c_str());
                 }
+#if defined(RT_OS_WINDOWS)
+                log = Utf8StrFmt("%s%cVBoxStartup.log",
+                                 logFolder.c_str(), RTPATH_DELIMITER);
+                RTFileDelete(log.c_str());
+#endif
 
                 RTDirRemove(logFolder.c_str());
             }
diff --git a/src/VBox/Main/src-server/MediumImpl.cpp b/src/VBox/Main/src-server/MediumImpl.cpp
index c61ea6f..3a935b5 100644
--- a/src/VBox/Main/src-server/MediumImpl.cpp
+++ b/src/VBox/Main/src-server/MediumImpl.cpp
@@ -2398,7 +2398,8 @@ STDMETHODIMP Medium::SetProperty(IN_BSTR aName, IN_BSTR aValue)
     Utf8Str strName(aName);
     Utf8Str strValue(aValue);
     settings::StringsMap::iterator it = m->mapProperties.find(strName);
-    if (!strName.startsWith("Special/"))
+    if (   !strName.startsWith("Special/")
+        && !isPropertyForFilter(strName))
     {
         if (it == m->mapProperties.end())
             return setError(VBOX_E_OBJECT_NOT_FOUND,
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index 3520c9c..e988800 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -54,7 +54,7 @@
  */
 
 /*
- * Copyright (C) 2007-2013 Oracle Corporation
+ * Copyright (C) 2007-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -2188,7 +2188,7 @@ bool MachineConfigFile::operator==(const MachineConfigFile &c) const
                  && (hardwareMachine            == c.hardwareMachine)       // this one's deep
                  && (storageMachine             == c.storageMachine)        // this one's deep
                  && (mediaRegistry              == c.mediaRegistry)         // this one's deep
-                 && (mapExtraDataItems          == c.mapExtraDataItems)     // this one's deep
+                 // skip mapExtraDataItems! there is no old state available as it's always forced
                  && (llFirstSnapshot            == c.llFirstSnapshot)       // this one's deep
                )
            );
@@ -5386,7 +5386,7 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
                     if (ctrl.strName != "OHCI")
                         fNonStdName = true;
                     break;
-               case USBControllerType_EHCI:
+                case USBControllerType_EHCI:
                     cEhciCtrls++;
                     if (ctrl.strName != "EHCI")
                         fNonStdName = true;
diff --git a/src/VBox/NetworkServices/NAT/proxy.c b/src/VBox/NetworkServices/NAT/proxy.c
index 51f29b4..ade529f 100644
--- a/src/VBox/NetworkServices/NAT/proxy.c
+++ b/src/VBox/NetworkServices/NAT/proxy.c
@@ -635,7 +635,7 @@ proxy_lwip_strerr(err_t error)
     static char buf[32];
     int e = -error;
 
-    if (0 < e || e < (int)__arraycount(lwiperr)) {
+    if (0 <= e && e < (int)__arraycount(lwiperr)) {
         return lwiperr[e];
     }
     else {
diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
index c533302..fe63353 100644
--- a/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
+++ b/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp
@@ -281,9 +281,9 @@ int netPfStrToPf(const char *pcszStrPortForward, int fIPv6, PPORTFORWARDRULE pPf
 
     cbRaw--;
 
-    if (     ((    fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0)
-              ||  (RTStrNICmp(pszRaw, "udp", 3) == 0))
-          && (pszRaw[3] == PF_FIELD_SEPARATOR)))
+    if (  (  (fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0))
+           ||              RTStrNICmp(pszRaw, "udp", 3) == 0)
+        && pszRaw[3] == PF_FIELD_SEPARATOR)
     {
         proto = (fTcpProto ? IPPROTO_TCP : IPPROTO_UDP);
         idxRaw = 3;
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk
index b015047..f6e234c 100644
--- a/src/VBox/Runtime/Makefile.kmk
+++ b/src/VBox/Runtime/Makefile.kmk
@@ -272,6 +272,7 @@ RuntimeR3_SOURCES       = \
 	common/asn1/asn1-basics.cpp \
 	common/asn1/asn1-cursor.cpp \
 	common/asn1/asn1-default-allocator.cpp \
+	common/asn1/asn1-efence-allocator.cpp \
 	common/asn1/asn1-dump.cpp \
 	common/asn1/asn1-encode.cpp \
 	common/asn1/asn1-ut-bitstring.cpp \
@@ -581,6 +582,7 @@ RuntimeR3_SOURCES       = \
 	generic/RTLogWriteStdErr-generic.cpp \
 	generic/RTLogWriteStdOut-generic.cpp \
 	generic/RTLogWriteUser-generic.cpp \
+	generic/RTPathGetCurrentDrive-generic.cpp \
 	generic/RTPathIsSame-generic.cpp \
 	generic/RTProcessQueryUsernameA-generic.cpp \
 	generic/RTTimerLRCreate-generic.cpp \
@@ -691,6 +693,7 @@ RuntimeR3_SOURCES.win = \
 	generic/RTFileExists-generic.cpp \
 	generic/RTMpGetCurFrequency-generic.cpp \
 	generic/RTMpGetMaxFrequency-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
 	generic/RTRandAdvCreateSystemFaster-generic.cpp \
 	generic/RTRandAdvCreateSystemTruer-generic.cpp \
 	generic/RTSemEventWait-generic.cpp \
@@ -758,6 +761,8 @@ RuntimeR3_SOURCES.linux = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
  	generic/RTSemEventMultiWait-2-ex-generic.cpp \
  	generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
@@ -843,6 +848,8 @@ RuntimeR3_SOURCES.os2   = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTRandAdvCreateSystemFaster-generic.cpp \
 	generic/RTRandAdvCreateSystemTruer-generic.cpp \
@@ -915,6 +922,8 @@ RuntimeR3_SOURCES.darwin = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTThreadGetAffinity-stub-generic.cpp \
 	generic/RTThreadSetAffinity-stub-generic.cpp \
@@ -983,6 +992,8 @@ RuntimeR3_SOURCES.freebsd = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
  	generic/RTSemEventMultiWait-2-ex-generic.cpp \
  	generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
 	generic/RTSystemQueryDmiString-generic.cpp \
@@ -1053,6 +1064,8 @@ RuntimeR3_SOURCES.solaris = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTProcIsRunningByName-generic.cpp \
  	generic/RTSemEventMultiWait-2-ex-generic.cpp \
@@ -1126,6 +1139,8 @@ RuntimeR3_SOURCES.haiku = \
 	generic/RTDirSetTimes-generic.cpp \
 	generic/RTFileMove-generic.cpp \
 	generic/RTLogWriteDebugger-generic.cpp \
+	generic/RTPathAbs-generic.cpp \
+	generic/RTPathGetCurrentOnDrive-generic.cpp \
 	generic/RTProcDaemonize-generic.cpp \
 	generic/RTTimeLocalNow-generic.cpp \
 	generic/RTTimerCreate-generic.cpp \
diff --git a/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp b/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp
new file mode 100644
index 0000000..efdac71
--- /dev/null
+++ b/src/VBox/Runtime/common/asn1/asn1-efence-allocator.cpp
@@ -0,0 +1,85 @@
+/* $Id: asn1-efence-allocator.cpp $ */
+/** @file
+ * IPRT - ASN.1, Electric Fense Allocator.
+ */
+
+/*
+ * Copyright (C) 2006-2014 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 "internal/iprt.h"
+#include <iprt/asn1.h>
+
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnFree} */
+static DECLCALLBACK(void) rtAsn1EFenceAllocator_Free(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation, void *pv)
+{
+    RTMemEfFreeNP(pv);
+    pAllocation->cbAllocated = 0;
+}
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnAlloc} */
+static DECLCALLBACK(int)  rtAsn1EFenceAllocator_Alloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation,
+                                                      void **ppv, size_t cb)
+{
+    void *pv = RTMemEfAllocZNP(cb, RTMEM_TAG);
+    if (pv)
+    {
+        *ppv = pv;
+        pAllocation->cbAllocated = (uint32_t)cb;
+        return VINF_SUCCESS;
+    }
+    return VERR_NO_MEMORY;
+}
+
+
+/** @interface_method_impl{RTASN1ALLOCATORVTABLE, pfnRealloc} */
+static DECLCALLBACK(int)  rtAsn1EFenceAllocator_Realloc(PCRTASN1ALLOCATORVTABLE pThis, PRTASN1ALLOCATION pAllocation,
+                                                        void *pvOld, void **ppvNew, size_t cbNew)
+{
+    Assert(pvOld);
+    Assert(cbNew);
+    void *pv = RTMemEfReallocNP(pvOld, cbNew, RTMEM_TAG);
+    if (pv)
+    {
+        *ppvNew = pv;
+        pAllocation->cbAllocated = (uint32_t)cbNew;
+        return VINF_SUCCESS;
+    }
+    return VERR_NO_MEMORY;
+}
+
+
+/** The Electric Fence ASN.1 allocator. */
+RT_DECL_DATA_CONST(RTASN1ALLOCATORVTABLE const) g_RTAsn1EFenceAllocator =
+{
+    rtAsn1EFenceAllocator_Free,
+    rtAsn1EFenceAllocator_Alloc,
+    rtAsn1EFenceAllocator_Realloc
+};
+
diff --git a/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp b/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
index f11a8ba..dc0750a 100644
--- a/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
+++ b/src/VBox/Runtime/common/asn1/asn1-ut-string.cpp
@@ -1439,7 +1439,7 @@ RTDECL(int) RTAsn1String_CompareWithString(PCRTASN1STRING pThis, const char *psz
                         iDiff = cch < cchString ? - 1 : 1;
                     break;
 
-                /** @todo Implement compating ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
+                /** @todo Implement comparing ASN1_TAG_BMP_STRING, ASN1_TAG_UNIVERSAL_STRING and
                  *        ASN1_TAG_T61_STRING with UTF-8 strings without conversion. */
 
                 default:
@@ -1527,7 +1527,7 @@ RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size
                     {
                         char           *pszDst = psz;
                         size_t          cchSrc = pThis->Asn1Core.cb;
-                        uint8_t const  *pbSrc  = (uint8_t const *)psz;
+                        uint8_t const  *pbSrc  = pThis->Asn1Core.uData.pu8;
                         while (cchSrc > 0)
                         {
                             RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[3], pbSrc[2], pbSrc[1], pbSrc[0]); /* big endian */
@@ -1546,7 +1546,7 @@ RTDECL(int) RTAsn1String_QueryUtf8(PCRTASN1STRING pThis, const char **ppsz, size
                     {
                         char           *pszDst = psz;
                         size_t          cchSrc = pThis->Asn1Core.cb;
-                        uint8_t const  *pbSrc  = (uint8_t const *)psz;
+                        uint8_t const  *pbSrc  = pThis->Asn1Core.uData.pu8;
                         while (cchSrc > 0)
                         {
                             RTUNICP uc = RT_MAKE_U32_FROM_U8(pbSrc[1], pbSrc[0], 0, 0); /* big endian */
diff --git a/src/VBox/Runtime/common/crypto/store-inmem.cpp b/src/VBox/Runtime/common/crypto/store-inmem.cpp
index 59015b1..53d0e15 100644
--- a/src/VBox/Runtime/common/crypto/store-inmem.cpp
+++ b/src/VBox/Runtime/common/crypto/store-inmem.cpp
@@ -31,6 +31,7 @@
 #include "internal/iprt.h"
 #include <iprt/crypto/store.h>
 
+#include <iprt/asm.h>
 #include <iprt/err.h>
 #include <iprt/mem.h>
 #include <iprt/string.h>
@@ -253,8 +254,9 @@ static DECLCALLBACK(PCRTCRCERTCTX) rtCrStoreInMem_CertSearchNext(void *pvProvide
     if (i < pThis->cCerts)
     {
         pSearch->auOpaque[1] = i + 1;
-        pThis->papCerts[i]->Core.cRefs++;
-        return &pThis->papCerts[i]->Core.Public;
+        PRTCRCERTCTXINT pCertCtx = &pThis->papCerts[i]->Core;
+        ASMAtomicIncU32(&pCertCtx->cRefs);
+        return &pCertCtx->Public;
     }
     return NULL;
 }
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
index 6e11da2..1091465 100644
--- a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
@@ -2938,6 +2938,7 @@ static PCRTDWARFABBREV rtDwarfAbbrev_LookupMiss(PRTDBGMODDWARF pThis, uint32_t u
             if (   pRet != NULL
                 && uCurCode >= pThis->cCachedAbbrevsAlloced)
                 break;
+            uPrevCode = uCurCode;
         }
     }
     else
diff --git a/src/VBox/Runtime/common/ldr/ldrMemory.cpp b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
index c402949..944b3a2 100644
--- a/src/VBox/Runtime/common/ldr/ldrMemory.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrMemory.cpp
@@ -314,7 +314,7 @@ RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH en
         pReader->pfnDestroy(pReader);
     }
     else
-        pfnDtor(pvUser),
+        pfnDtor(pvUser);
     *phLdrMod = NIL_RTLDRMOD;
 
     LogFlow(("RTLdrOpen: return %Rrc\n", rc));
diff --git a/src/VBox/Runtime/common/ldr/ldrPE.cpp b/src/VBox/Runtime/common/ldr/ldrPE.cpp
index e470136..c460d15 100644
--- a/src/VBox/Runtime/common/ldr/ldrPE.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrPE.cpp
@@ -1595,7 +1595,7 @@ static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDREN
         if (SegInfo.cchName >= sizeof(pSh->Name))
         {
             memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
-            szName[sizeof(sizeof(pSh->Name))] = '\0';
+            szName[sizeof(pSh->Name)] = '\0';
             SegInfo.pszName = szName;
         }
         else if (SegInfo.cchName == 0)
diff --git a/src/VBox/Runtime/common/string/strformat.cpp b/src/VBox/Runtime/common/string/strformat.cpp
index 335d303..61fd186 100644
--- a/src/VBox/Runtime/common/string/strformat.cpp
+++ b/src/VBox/Runtime/common/string/strformat.cpp
@@ -181,7 +181,7 @@ static int rtStrFormatNumber(char *psz, KSIZE64 ullValue, unsigned int uiBase, s
     /*
      * Validate and adjust input...
      */
-    Assert(uiBase >= 2 || uiBase <= 16);
+    Assert(uiBase >= 2 && uiBase <= 16);
     if (fFlags & RTSTR_F_CAPITAL)
         pachDigits = "0123456789ABCDEF";
     if (fFlags & RTSTR_F_LEFT)
diff --git a/src/VBox/Runtime/common/string/utf-16.cpp b/src/VBox/Runtime/common/string/utf-16.cpp
index 63c9931..d684bc9 100644
--- a/src/VBox/Runtime/common/string/utf-16.cpp
+++ b/src/VBox/Runtime/common/string/utf-16.cpp
@@ -99,6 +99,20 @@ static int rtUtf16Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcuc, size_t *pcwcA
 }
 
 
+RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag)
+{
+    if (cb > sizeof(RTUTF16))
+        cb = RT_ALIGN_Z(cb, sizeof(RTUTF16));
+    else
+        cb = sizeof(RTUTF16);
+    PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag(cb, pszTag);
+    if (pwsz)
+        *pwsz = '\0';
+    return pwsz;
+}
+RT_EXPORT_SYMBOL(RTUtf16AllocTag);
+
+
 RTDECL(void)  RTUtf16Free(PRTUTF16 pwszString)
 {
     if (pwszString)
diff --git a/src/VBox/Runtime/common/time/time.cpp b/src/VBox/Runtime/common/time/time.cpp
index f16911a..c47caca 100644
--- a/src/VBox/Runtime/common/time/time.cpp
+++ b/src/VBox/Runtime/common/time/time.cpp
@@ -452,7 +452,7 @@ static PRTTIME rtTimeNormalizeInternal(PRTTIME pTime)
         {
             unsigned cDaysInMonth = fLeapYear
                                   ? g_acDaysInMonthsLeap[pTime->u8Month - 1]
-                                  : g_acDaysInMonthsLeap[pTime->u8Month - 1];
+                                  : g_acDaysInMonths[pTime->u8Month - 1];
             if (pTime->u8MonthDay <= cDaysInMonth)
                 break;
             pTime->u8MonthDay -= cDaysInMonth;
diff --git a/src/VBox/Runtime/generic/RTPathAbs-generic.cpp b/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
new file mode 100644
index 0000000..72ea7bb
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathAbs-generic.cpp
@@ -0,0 +1,358 @@
+/* $Id: RTPathAbs-generic.cpp $ */
+/** @file
+ * IPRT - RTPathAbs, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2014 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                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+#include "internal/fs.h"
+
+
+static char *rtPathSkipRootSpec(char *pszCur)
+{
+#ifdef HAVE_DRIVE
+    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == RTPATH_SLASH)
+        pszCur += 3;
+# ifdef HAVE_UNC
+    else if (pszCur[0] == RTPATH_SLASH && pszCur[1] == RTPATH_SLASH)
+    {
+        pszCur += 2;
+        while (*pszCur == RTPATH_SLASH)
+            pszCur++;
+        if (*pszCur)
+        {
+            while (*pszCur != RTPATH_SLASH && *pszCur)
+                pszCur++;
+            if (*pszCur == RTPATH_SLASH)
+            {
+                pszCur++;
+                while (*pszCur != RTPATH_SLASH && *pszCur)
+                    pszCur++;
+                if (*pszCur == RTPATH_SLASH)
+                    pszCur++;
+            }
+        }
+    }
+# endif
+#else
+    if (pszCur[0] == RTPATH_SLASH)
+        pszCur += 1;
+#endif
+    return pszCur;
+}
+
+
+/**
+ * Cleans up a path specifier a little bit.
+ *
+ * This includes removing duplicate slashes, unnecessary single dots, and
+ * trailing slashes. Also, replaces all slash characters with RTPATH_SLASH.
+ *
+ * @returns Length of the cleaned path (in chars).
+ * @param   pszPath     The path to cleanup.
+ */
+static int fsCleanPath(char *pszPath)
+{
+    char *pszSrc = pszPath;
+    char *pszTrg = pszPath;
+
+    /*
+     * On windows, you either use on or two slashes at the head of a path,
+     * seems like it treats additional slashes as part of the UNC server name.
+     * Just change slashes to RTPATH_SLASH and skip them.
+     */
+    /** @todo check how OS/2 treats unnecessary leading slashes */
+    int cchIgnoreLeading = 0;
+#ifdef HAVE_UNC
+    if (   RTPATH_IS_SLASH(pszSrc[0])
+        && RTPATH_IS_SLASH(pszSrc[1]))
+    {
+        pszTrg[0] = RTPATH_SLASH;
+        pszTrg[1] = RTPATH_SLASH;
+        pszTrg += 2;
+        pszSrc += 2;
+        cchIgnoreLeading = 1;
+        while (RTPATH_IS_SLASH(*pszSrc))
+        {
+            cchIgnoreLeading++;
+            pszSrc++;
+            *pszTrg++ = RTPATH_SLASH;
+        }
+    }
+#endif
+
+    /*
+     * Change slashes to RTPATH_SLASH and remove duplicates.
+     */
+    for (;;)
+    {
+        char ch = *pszSrc++;
+        if (RTPATH_IS_SLASH(ch))
+        {
+            *pszTrg++ = RTPATH_SLASH;
+            for (;;)
+            {
+                do
+                    ch = *pszSrc++;
+                while (RTPATH_IS_SLASH(ch));
+
+                /* Remove '/./' and '/.'. */
+                if (   ch != '.'
+                    || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
+                    break;
+            }
+        }
+        *pszTrg = ch;
+        if (!ch)
+            break;
+        pszTrg++;
+    }
+
+    return pszTrg - pszPath;
+}
+
+
+RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+{
+    int rc;
+
+    /*
+     * Validation.
+     */
+    AssertPtr(pszAbsPath);
+    AssertPtr(pszPath);
+    if (RT_UNLIKELY(!*pszPath))
+        return VERR_INVALID_PARAMETER; //VERR_INVALID_NAME;
+
+    /*
+     * Make a clean working copy of the input.
+     */
+    size_t cchPath = strlen(pszPath);
+    if (cchPath >= RTPATH_MAX)
+    {
+        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
+        return VERR_FILENAME_TOO_LONG;
+    }
+
+    char szTmpPath[RTPATH_MAX];
+    memcpy(szTmpPath, pszPath, cchPath + 1);
+    size_t cchTmpPath = fsCleanPath(szTmpPath);
+
+    /*
+     * Handle "." specially (fsCleanPath does).
+     */
+    if (szTmpPath[0] == '.')
+    {
+        if (   cchTmpPath == 1
+            || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
+        {
+            rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
+            if (RT_SUCCESS(rc))
+            {
+                size_t cch = fsCleanPath(pszAbsPath);
+                char  *pszTop = rtPathSkipRootSpec(pszAbsPath);
+#if 1
+                if ((uintptr_t)&pszAbsPath[cch] > (uintptr_t)pszTop && pszAbsPath[cch - 1] == RTPATH_SLASH)
+                    pszAbsPath[cch - 1] = '\0';
+#else
+                if (   cchTmpPath == 2
+                    && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
+                {
+                    if (cch + 1 < cchAbsPath)
+                    {
+                        pszAbsPath[cch++] = RTPATH_SLASH;
+                        pszAbsPath[cch] = '\0';
+                    }
+                    else
+                        rc = VERR_BUFFER_OVERFLOW;
+                }
+#endif
+            }
+            return rc;
+        }
+    }
+
+    /*
+     * Do we have an incomplete root spec?  Supply the missing bits.
+     */
+#ifdef HAVE_DRIVE
+    if (   !(szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] == RTPATH_SLASH)
+# ifdef HAVE_UNC
+        && !(szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] == RTPATH_SLASH)
+# endif
+        )
+#else
+    if (szTmpPath[0] != RTPATH_SLASH)
+#endif
+    {
+        char    szCurDir[RTPATH_MAX];
+        size_t  cchCurDir;
+        int     offApplyAt;
+        bool    fNeedSlash;
+#ifdef HAVE_DRIVE
+        if (szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] != RTPATH_SLASH)
+        {
+            /*
+             * Relative to drive specific current directory.
+             */
+            rc = RTPathGetCurrentOnDrive(szTmpPath[0], szCurDir, sizeof(szCurDir));
+            fNeedSlash = true;
+            offApplyAt = 2;
+        }
+# ifdef HAVE_UNC
+        else if (szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] != RTPATH_SLASH)
+# else
+        else if (szTmpPath[0] == RTPATH_SLASH)
+# endif
+        {
+            /*
+             * Root of current drive.  This may return a UNC root if we're not
+             * standing on a drive but on a UNC share.
+             */
+            rc = RTPathGetCurrentDrive(szCurDir, sizeof(szCurDir));
+            fNeedSlash = false;
+            offApplyAt = 0;
+        }
+        else
+#endif
+        {
+            /*
+             * Relative to current directory.
+             */
+            rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
+            fNeedSlash = true;
+            offApplyAt = 0;
+        }
+        if (RT_SUCCESS(rc))
+        {
+            cchCurDir = fsCleanPath(szCurDir);
+            if (fNeedSlash && cchCurDir > 0 && szCurDir[cchCurDir - 1] == RTPATH_SLASH)
+                fNeedSlash = false;
+
+            if (cchCurDir + fNeedSlash + cchTmpPath - offApplyAt <= RTPATH_MAX)
+            {
+                memmove(szTmpPath + cchCurDir + fNeedSlash, szTmpPath + offApplyAt, cchTmpPath + 1 - offApplyAt);
+                memcpy(szTmpPath, szCurDir, cchCurDir);
+                if (fNeedSlash)
+                    szTmpPath[cchCurDir] = RTPATH_SLASH;
+            }
+            else
+                rc = VERR_FILENAME_TOO_LONG;
+        }
+        if (RT_FAILURE(rc))
+        {
+            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
+            return rc;
+        }
+    }
+
+    /*
+     * Skip past the root spec.
+     */
+    char *pszCur = rtPathSkipRootSpec(szTmpPath);
+    AssertMsgReturn(pszCur != &szTmpPath[0], ("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
+    char * const pszTop = pszCur;
+
+    /*
+     * Get rid of double dot path components by evaluating them.
+     */
+    for (;;)
+    {
+        if (   pszCur[0] == '.'
+            && pszCur[1] == '.'
+            && (!pszCur[2] || pszCur[2] == RTPATH_SLASH))
+        {
+            /* rewind to the previous component if any */
+            char *pszPrev = pszCur;
+            if ((uintptr_t)pszPrev > (uintptr_t)pszTop)
+            {
+                pszPrev--;
+                while (   (uintptr_t)pszPrev > (uintptr_t)pszTop
+                       && pszPrev[-1] != RTPATH_SLASH)
+                    pszPrev--;
+            }
+            if (!pszCur[2])
+            {
+                if (pszPrev != pszTop)
+                    pszPrev[-1] = '\0';
+                else
+                    *pszPrev = '\0';
+                break;
+            }
+            Assert(pszPrev[-1] == RTPATH_SLASH);
+            memmove(pszPrev, pszCur + 3, strlen(pszCur + 3) + 1);
+            pszCur = pszPrev - 1;
+        }
+        else
+        {
+            /* advance to end of component. */
+            while (*pszCur && *pszCur != RTPATH_SLASH)
+                pszCur++;
+        }
+
+        if (!*pszCur)
+            break;
+
+        /* skip the slash */
+        ++pszCur;
+    }
+
+    cchTmpPath = pszCur - szTmpPath;
+
+#if 1
+    /*
+     * Strip trailing slash if that's what's desired.
+     */
+
+    if ((uintptr_t)&szTmpPath[cchTmpPath] > (uintptr_t)pszTop && szTmpPath[cchTmpPath - 1] == RTPATH_SLASH)
+        szTmpPath[--cchTmpPath] = '\0';
+#endif
+
+    /*
+     * Copy the result to the user buffer.
+     */
+    if (cchTmpPath < cchAbsPath)
+    {
+        memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
+        rc = VINF_SUCCESS;
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
+
+    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
+             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
+    return rc;
+}
+
diff --git a/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp b/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
new file mode 100644
index 0000000..f5706b2
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathGetCurrentDrive-generic.cpp
@@ -0,0 +1,106 @@
+/* $Id: RTPathGetCurrentDrive-generic.cpp $ */
+/** @file
+ * IPRT - RTPathGetCurrentDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 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                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+    /*
+     * Query the current directroy and extract the wanted information from it.
+     */
+    int rc = RTPathGetCurrent(pszPath, cbPath);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Drive letter? Chop off at root slash.
+         */
+        if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
+        {
+            pszPath[2] = '\0';
+            return rc;
+        }
+
+        /*
+         * UNC? Chop off after share.
+         */
+        if (   RTPATH_IS_SLASH(pszPath[0])
+            && RTPATH_IS_SLASH(pszPath[1])
+            && !RTPATH_IS_SLASH(pszPath[2])
+            && pszPath[2])
+        {
+            /* Work thru the server name. */
+            size_t off = 3;
+            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                off++;
+            size_t offServerSlash = off;
+
+            /* Is there a share name? */
+            if (RTPATH_IS_SLASH(pszPath[off]))
+            {
+                while (RTPATH_IS_SLASH(pszPath[off]))
+                    off++;
+                if (pszPath[off])
+                {
+                    /* Work thru the share name. */
+                    while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
+                        off++;
+                }
+                /* No share name, chop at server name. */
+                else
+                    off = offServerSlash;
+            }
+        }
+        return VERR_INTERNAL_ERROR_4;
+    }
+    return rc;
+
+#else  /* !HAVE_DRIVE */
+    /*
+     * No drive letters on this system, return empty string.
+     */
+    if (cbPath > 0)
+    {
+        *pszPath = '\0';
+        return VINF_SUCCESS;
+    }
+    return VERR_BUFFER_OVERFLOW;
+#endif /* !HAVE_DRIVE */
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentDrive);
+
diff --git a/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp b/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp
new file mode 100644
index 0000000..09a8eb2
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTPathGetCurrentOnDrive-generic.cpp
@@ -0,0 +1,84 @@
+/* $Id: RTPathGetCurrentOnDrive-generic.cpp $ */
+/** @file
+ * IPRT - RTPathGetCurrentOnDrive, generic implementation.
+ */
+
+/*
+ * Copyright (C) 2014 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                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_PATH
+#include <iprt/path.h>
+#include "internal/iprt.h"
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+#ifdef HAVE_DRIVE
+    /*
+     * Check if it's the same drive as the current directory.
+     */
+    int rc = RTPathGetCurrent(pszPath, cbPath);
+    if (RT_SUCCESS(rc))
+    {
+        if (   (   chDrive == *pszPath
+                || RT_C_TO_LOWER(chDrive) == RT_C_TO_LOWER(*pszPath))
+            && RTPATH_IS_VOLSEP(pszPath[1]))
+            return rc;
+
+        /*
+         * Different drive, indicate root.
+         */
+        if (cbPath >= 4)
+        {
+            pszPath[0] = RT_C_TO_UPPER(chDrive);
+            pszPath[1] = ':';
+            pszPath[2] = RTPATH_SLASH;
+            pszPath[3] = '\0';
+            return VINF_SUCCESS;
+        }
+    }
+    return rc;
+
+#else
+    /*
+     * No driver letters, just return root slash on whatever we're asked.
+     */
+    NOREF(chDrive);
+    if (cbPath >= 2)
+    {
+        pszPath[0] = RTPATH_SLASH;
+        pszPath[1] = '\0';
+        return VINF_SUCCESS;
+    }
+    return VERR_BUFFER_OVERFLOW;
+#endif
+}
+RT_EXPORT_SYMBOL(RTPathGetCurrentOnDrive);
+
diff --git a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
index dc1f7a8..7c6064a 100644
--- a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
@@ -164,7 +164,7 @@ static PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
     pVmArea->nr_pages = 0;    /* paranoia? */
     pVmArea->pages    = NULL; /* paranoia? */
 
-    papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL);
+    papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL | __GFP_NOWARN);
     if (!papPages)
     {
         vunmap(pVmArea->addr);
@@ -254,11 +254,11 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
 
 # else  /* !RTMEMALLOC_EXEC_HEAP */
 # error "you don not want to go here..."
-        pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
+        pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
 # endif /* !RTMEMALLOC_EXEC_HEAP */
 
 #elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
-        pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
+        pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, MY_PAGE_KERNEL_EXEC);
 #else
         pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
 #endif
@@ -276,7 +276,8 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
         {
             fFlags |= RTMEMHDR_FLAG_KMALLOC;
             pHdr = kmalloc(cb + sizeof(*pHdr),
-                           (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? GFP_ATOMIC : GFP_KERNEL);
+                           (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? (GFP_ATOMIC | __GFP_NOWARN)
+                                                                  : (GFP_KERNEL | __GFP_NOWARN));
             if (RT_UNLIKELY(   !pHdr
                             && cb > PAGE_SIZE
                             && !(fFlags & RTMEMHDR_FLAG_ANY_CTX) ))
diff --git a/src/VBox/Runtime/r3/memsafer-r3.cpp b/src/VBox/Runtime/r3/memsafer-r3.cpp
index fc07a06..63b86dd 100644
--- a/src/VBox/Runtime/r3/memsafer-r3.cpp
+++ b/src/VBox/Runtime/r3/memsafer-r3.cpp
@@ -285,6 +285,15 @@ static int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
         rtMemSaferInitializePages(pThis, pvPages);
 
         /*
+         * On darwin we cannot allocate pages without an R0 mapping and
+         * SUPR3PageAllocEx falls back to another method which is incompatible with
+         * the way SUPR3PageProtect works. Ignore changing the protection of the guard
+         * pages.
+         */
+#ifdef RT_OS_DARWIN
+        return VINF_SUCCESS;
+#else
+        /*
          * Configure the guard pages.
          * SUPR3PageProtect isn't supported on all hosts, we ignore that.
          */
@@ -301,6 +310,7 @@ static int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
 
         /* failed. */
         int rc2 = SUPR3PageFreeEx(pvPages, pThis->cPages); AssertRC(rc2);
+#endif
     }
     return rc;
 #else  /* !IN_SUP_R3 */
diff --git a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
index f93f6e4..ea2d1e3 100644
--- a/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
@@ -104,7 +104,7 @@ int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
 #ifdef IPRT_WITH_NT_PATH_PASSTHRU
     bool fObjDir;
 #endif
-    rc = rtNtPathOpenDir(pszPathBuf,
+    rc = RTNtPathOpenDir(pszPathBuf,
                          FILE_READ_DATA | SYNCHRONIZE,
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
                          FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
@@ -148,11 +148,11 @@ RTDECL(int) RTDirClose(PRTDIR pDir)
      * Close the handle.
      */
     pDir->u32Magic = ~RTDIR_MAGIC;
-    if (pDir->hDir != MY_INVALID_HANDLE_VALUE)
+    if (pDir->hDir != RTNT_INVALID_HANDLE_VALUE)
     {
-        int rc = rtNtPathClose(pDir->hDir);
+        int rc = RTNtPathClose(pDir->hDir);
         AssertRC(rc);
-        pDir->hDir = MY_INVALID_HANDLE_VALUE;
+        pDir->hDir = RTNT_INVALID_HANDLE_VALUE;
     }
     RTStrFree(pDir->pszName);
     pDir->pszName = NULL;
@@ -280,7 +280,7 @@ static int rtDirNtFetchMore(PRTDIR pThis)
      * Read more.
      */
     NTSTATUS rcNt;
-    IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
     if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
     {
 #ifdef IPRT_WITH_NT_PATH_PASSTHRU
diff --git a/src/VBox/Runtime/r3/nt/fs-nt.cpp b/src/VBox/Runtime/r3/nt/fs-nt.cpp
index 314059d..e89b55b 100644
--- a/src/VBox/Runtime/r3/nt/fs-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/fs-nt.cpp
@@ -52,7 +52,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
      * Open the file/dir/whatever.
      */
     HANDLE hFile;
-    int rc = rtNtPathOpen(pszFsPath,
+    int rc = RTNtPathOpen(pszFsPath,
                           GENERIC_READ,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -67,7 +67,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
          * Get the volume information.
          */
         FILE_FS_SIZE_INFORMATION FsSizeInfo;
-        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsSizeInfo, sizeof(FsSizeInfo), FileFsSizeInformation);
         if (NT_SUCCESS(rcNt))
         {
@@ -107,7 +107,7 @@ RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pc
         else
             rc = RTErrConvertFromNtStatus(rcNt);
 
-        rtNtPathClose(hFile);
+        RTNtPathClose(hFile);
     }
     return rc;
 }
@@ -125,7 +125,7 @@ RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
      * Open the file/dir/whatever.
      */
     HANDLE hFile;
-    int rc = rtNtPathOpen(pszFsPath,
+    int rc = RTNtPathOpen(pszFsPath,
                           GENERIC_READ,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -144,14 +144,14 @@ RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
              FILE_FS_VOLUME_INFORMATION FsVolInfo;
              uint8_t abBuf[sizeof(FILE_FS_VOLUME_INFORMATION) + 4096];
         } u;
-        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsVolumeInformation);
         if (NT_SUCCESS(rcNt))
             *pu32Serial = u.FsVolInfo.VolumeSerialNumber;
         else
             rc = RTErrConvertFromNtStatus(rcNt);
 
-        rtNtPathClose(hFile);
+        RTNtPathClose(hFile);
     }
     return rc;
 }
@@ -169,7 +169,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
      * Open the file/dir/whatever.
      */
     HANDLE hFile;
-    int rc = rtNtPathOpen(pszFsPath,
+    int rc = RTNtPathOpen(pszFsPath,
                           GENERIC_READ,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -188,7 +188,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
             FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
             uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
         } u;
-        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
         if (NT_SUCCESS(rcNt))
         {
@@ -219,7 +219,7 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
         else
             rc = RTErrConvertFromNtStatus(rcNt);
 
-        rtNtPathClose(hFile);
+        RTNtPathClose(hFile);
     }
     return rc;
 }
@@ -239,7 +239,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
      * Open the file/dir/whatever.
      */
     HANDLE hFile;
-    int rc = rtNtPathOpen(pszFsPath,
+    int rc = RTNtPathOpen(pszFsPath,
                           GENERIC_READ,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -258,7 +258,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
             FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
             uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096];
         } u;
-        IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
+        IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation);
         if (NT_SUCCESS(rcNt))
         {
@@ -277,7 +277,7 @@ RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
         else
             rc = RTErrConvertFromNtStatus(rcNt);
 
-        rtNtPathClose(hFile);
+        RTNtPathClose(hFile);
     }
     return rc;
 }
diff --git a/src/VBox/Runtime/r3/nt/internal-r3-nt.h b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
index 0a97096..f2d33ca 100644
--- a/src/VBox/Runtime/r3/nt/internal-r3-nt.h
+++ b/src/VBox/Runtime/r3/nt/internal-r3-nt.h
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-2013 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -28,38 +28,14 @@
 #ifndef ___internal_r3_nt_h___
 #define ___internal_r3_nt_h___
 
-
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#include <ntstatus.h>
-#ifdef IPRT_NT_USE_WINTERNL
-# define WIN32_NO_STATUS
-# include <windef.h>
-# include <winnt.h>
-# include <winternl.h>
-# define IPRT_NT_NEED_API_GROUP_1
-
-#elif defined(IPRT_NT_USE_WDM)
-# include <wdm.h>
-# define IPRT_NT_NEED_API_GROUP_1
-
+#ifdef IN_SUP_HARDENED_R3
+# include <iprt/nt/nt-and-windows.h>
 #else
-# include <ntifs.h>
+# include <iprt/nt/nt.h>
 #endif
 #include "internal/iprt.h"
 
 
-/*******************************************************************************
-*   Defined Constants And Macros                                               *
-*******************************************************************************/
-/** Indicates that we're targetting native NT in the current source. */
-#define RT_USE_NATIVE_NT                1
-/** Initializes a IO_STATUS_BLOCK. */
-#define MY_IO_STATUS_BLOCK_INITIALIZER  { STATUS_FAILED_DRIVER_ENTRY, ~(uintptr_t)42 }
-/** Similar to INVALID_HANDLE_VALUE in the Windows environment. */
-#define MY_INVALID_HANDLE_VALUE         ( (HANDLE)~(uintptr_t)0 )
-
 #ifdef DEBUG_bird
 /** Enables the "\\!\" NT path pass thru as well as hacks for listing NT object
  * directories. */
@@ -67,17 +43,6 @@
 #endif
 
 
-/*******************************************************************************
-*   Internal Functions                                                         *
-*******************************************************************************/
-int  rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                  ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
-                  PHANDLE phHandle, PULONG_PTR puDisposition);
-int  rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
-                     ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir);
-int  rtNtPathClose(HANDLE hHandle);
-
-
 /**
  * Internal helper for comparing a WCHAR string with a char string.
  *
@@ -101,40 +66,5 @@ DECLINLINE(bool) rtNtCompWideStrAndAscii(WCHAR const *pwsz1, size_t cch1, const
     return true;
 }
 
-
-/*******************************************************************************
-*   NT APIs                                                                    *
-*******************************************************************************/
-
-RT_C_DECLS_BEGIN
-
-#ifdef IPRT_NT_NEED_API_GROUP_1
-
-typedef struct _FILE_FS_ATTRIBUTE_INFORMATION
-{
-    ULONG   FileSystemAttributes;
-    LONG    MaximumComponentNameLength;
-    ULONG   FileSystemNameLength;
-    WCHAR   FileSystemName[1];
-} FILE_FS_ATTRIBUTE_INFORMATION;
-typedef FILE_FS_ATTRIBUTE_INFORMATION *PFILE_FS_ATTRIBUTE_INFORMATION;
-extern "C" NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FS_INFORMATION_CLASS);
-
-#endif
-
-NTSTATUS NTAPI NtOpenDirectoryObject(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
-
-typedef struct _OBJECT_DIRECTORY_INFORMATION
-{
-    UNICODE_STRING Name;
-    UNICODE_STRING TypeName;
-} OBJECT_DIRECTORY_INFORMATION;
-typedef OBJECT_DIRECTORY_INFORMATION *POBJECT_DIRECTORY_INFORMATION;
-
-NTSTATUS NTAPI NtQueryDirectoryObject(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
-
-
-RT_C_DECLS_END
-
 #endif
 
diff --git a/src/VBox/Runtime/r3/nt/pathint-nt.cpp b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
index a68f059..aedbc0d 100644
--- a/src/VBox/Runtime/r3/nt/pathint-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/pathint-nt.cpp
@@ -37,16 +37,22 @@
 #include <iprt/assert.h>
 
 
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static char const g_szPrefixUnc[] = "\\??\\UNC\\";
+static char const g_szPrefix[]    = "\\??\\";
+
 
 /**
- * Handles the pass thru case.
+ * Handles the pass thru case for UTF-8 input.
  *
  * @returns IPRT status code.
  * @param   pNtName             Where to return the NT name.
  * @param   phRootDir           Where to return the root handle, if applicable.
  * @param   pszPath             The UTF-8 path.
  */
-static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
     PRTUTF16 pwszPath = NULL;
     size_t   cwcLen;
@@ -60,7 +66,8 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
             pwszPath[2] = '\\';
 
             pNtName->Buffer = pwszPath;
-            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
             *phRootDir = NULL;
             return VINF_SUCCESS;
         }
@@ -73,6 +80,56 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
 
 
 /**
+ * Handles the pass thru case for UTF-16 input.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.
+ * @param   phRootDir           Stores NULL here, as we don't use it.
+ * @param   pwszWinPath         The UTF-16 windows-style path.
+ * @param   cwcWinPath          The length of the windows-style input path.
+ */
+static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
+                                        PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+    /* Drop a character because: \\?\ -> \.\ */
+    pwszWinPath++;
+    cwcWinPath--;
+
+    /* Check length and allocate memory for it. */
+    int rc;
+    if (cwcWinPath < _32K - 1)
+    {
+        PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+        if (pwszNtPath)
+        {
+            /* Intialize the path. */
+            pwszNtPath[0] = '\\';
+            pwszNtPath[1] = '.';
+            pwszNtPath[2] = '\\';
+            memcpy(pwszNtPath + 3, pwszWinPath + 3, (cwcWinPath - 3) * sizeof(RTUTF16));
+            pwszNtPath[cwcWinPath] = '\0';
+
+            /* Initialize the return values. */
+            pNtName->Buffer = pwszNtPath;
+            pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+            *phRootDir = NULL;
+
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_NO_UTF16_MEMORY;
+    }
+    else
+        rc = VERR_FILENAME_TOO_LONG;
+    return rc;
+}
+
+
+
+
+
+/**
  * Converts the path to UTF-16 and sets all the return values.
  *
  * @returns IPRT status code.
@@ -80,7 +137,7 @@ static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE
  * @param   phRootDir           Where to return the root handle, if applicable.
  * @param   pszPath             The UTF-8 path.
  */
-static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
+static int rtNtPathUtf8ToUniStr(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
     PRTUTF16 pwszPath = NULL;
     size_t   cwcLen;
@@ -90,7 +147,8 @@ static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRo
         if (cwcLen < _32K - 1)
         {
             pNtName->Buffer = pwszPath;
-            pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
+            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
+            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
             *phRootDir = NULL;
             return VINF_SUCCESS;
         }
@@ -112,14 +170,11 @@ static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRo
  */
 static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
 {
-    static char const s_szPrefixUnc[] = "\\??\\UNC\\";
-    static char const s_szPrefix[]    = "\\??\\";
-
     /*
      * Very simple conversion of a win32-like path into an NT path.
      */
-    const char *pszPrefix = s_szPrefix;
-    size_t      cchPrefix = sizeof(s_szPrefix) - 1;
+    const char *pszPrefix = g_szPrefix;
+    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
     size_t      cchSkip   = 0;
 
     if (   RTPATH_IS_SLASH(pszPath[0])
@@ -129,13 +184,13 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
     {
         if (   pszPath[2] == '?'
             && RTPATH_IS_SLASH(pszPath[3]))
-            return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
+            return rtNtPathFromWinUtf8PassThru(pNtName, phRootDir, pszPath);
 
 #ifdef IPRT_WITH_NT_PATH_PASSTHRU
         /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
         if (   pszPath[2] == '!'
             && RTPATH_IS_SLASH(pszPath[3]))
-            return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
+            return rtNtPathUtf8ToUniStr(pNtName, phRootDir, pszPath + 3);
 #endif
 
         if (   pszPath[2] == '.'
@@ -150,8 +205,8 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
         else
         {
             /* UNC */
-            pszPrefix = s_szPrefixUnc;
-            cchPrefix = sizeof(s_szPrefixUnc) - 1;
+            pszPrefix = g_szPrefixUnc;
+            cchPrefix = sizeof(g_szPrefixUnc) - 1;
             cchSkip   = 2;
         }
     }
@@ -168,7 +223,119 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
      * Add prefix and convert it to UTF16.
      */
     memcpy(szPath, pszPrefix, cchPrefix);
-    return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
+    return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
+}
+
+
+/**
+ * Converts a UTF-16 windows-style path to NT format.
+ *
+ * @returns IPRT status code.
+ * @param   pNtName             Where to return the NT name.  Free using
+ *                              RTNtPathFree.
+ * @param   phRootDir           Where to return the root handle, if applicable.
+ * @param   pwszWinPath         The UTF-16 windows-style path.
+ * @param   cwcWinPath          The max length of the windows-style path in
+ *                              RTUTF16 units.  Use RTSTR_MAX if unknown and @a
+ *                              pwszWinPath is correctly terminated.
+ */
+RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszWinPath, size_t cwcWinPath)
+{
+    /*
+     * Validate the input, calculating the correct length.
+     */
+    if (cwcWinPath == 0 || *pwszWinPath == '\0')
+        return VERR_INVALID_NAME;
+
+    RTUtf16NLenEx(pwszWinPath, cwcWinPath, &cwcWinPath);
+    int rc = RTUtf16ValidateEncodingEx(pwszWinPath, cwcWinPath, 0);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Very simple conversion of a win32-like path into an NT path.
+     */
+    const char *pszPrefix = g_szPrefix;
+    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
+    size_t      cchSkip   = 0;
+
+    if (   RTPATH_IS_SLASH(pwszWinPath[0])
+        && cwcWinPath >= 3
+        && RTPATH_IS_SLASH(pwszWinPath[1])
+        && !RTPATH_IS_SLASH(pwszWinPath[2]) )
+    {
+        if (   pwszWinPath[2] == '?'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+            return rtNtPathFromWinUtf16PassThru(pNtName, phRootDir, pwszWinPath, cwcWinPath);
+
+#ifdef IPRT_WITH_NT_PATH_PASSTHRU
+        /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
+        if (   pwszWinPath[2] == '!'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+        {
+            pwszWinPath += 3;
+            cwcWinPath  -= 3;
+            if (cwcWinPath < _32K - 1)
+            {
+                PRTUTF16 pwszNtPath = RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
+                if (pwszNtPath)
+                {
+                    memcpy(pwszNtPath, pwszWinPath, cwcWinPath * sizeof(RTUTF16));
+                    pwszNtPath[cwcWinPath] = '\0';
+                    pNtName->Buffer = pwszNtPath;
+                    pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
+                    pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
+                    *phRootDir = NULL;
+                    return VINF_SUCCESS;
+                }
+                rc = VERR_NO_UTF16_MEMORY;
+            }
+            else
+                rc = VERR_FILENAME_TOO_LONG;
+            return rc;
+        }
+#endif
+
+        if (   pwszWinPath[2] == '.'
+            && cwcWinPath >= 4
+            && RTPATH_IS_SLASH(pwszWinPath[3]))
+        {
+            /*
+             * Device path.
+             * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
+             */
+            cchSkip   = 4;
+        }
+        else
+        {
+            /* UNC */
+            pszPrefix = g_szPrefixUnc;
+            cchPrefix = sizeof(g_szPrefixUnc) - 1;
+            cchSkip   = 2;
+        }
+    }
+
+    /*
+     * Straighten out all .. and unnecessary . references and convert slashes.
+     */
+    char   szAbsPath[RTPATH_MAX];
+    char   szRelPath[RTPATH_MAX];
+    char  *pszRelPath = szRelPath;
+    size_t cchRelPath;
+    rc = RTUtf16ToUtf8Ex(pwszWinPath, cwcWinPath, &pszRelPath, sizeof(szRelPath), &cchRelPath);
+    if (RT_SUCCESS(rc))
+        rc = RTPathAbs(szRelPath, &szAbsPath[cchPrefix - cchSkip], sizeof(szAbsPath) - (cchPrefix - cchSkip));
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Add prefix and convert it to UTF16.
+         */
+        memcpy(szAbsPath, pszPrefix, cchPrefix);
+        return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szAbsPath);
+    }
+    return rc;
 }
 
 
@@ -180,7 +347,7 @@ static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
  * @param   phRootDir           The root handle variable after a
  *                              rtNtPathToNative.
  */
-void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
+static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
 {
     RTUtf16Free(pNtName->Buffer);
     pNtName->Buffer = NULL;
@@ -188,6 +355,20 @@ void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
 
 
 /**
+ * Frees the native path and root handle.
+ *
+ * @param   pNtName             The NT path after a successful
+ *                              RTNtPathFromWinUtf16Ex call.
+ * @param   phRootDir           The root handle variable after a successfull
+ *                              RTNtPathFromWinUtf16Ex call.
+ */
+RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
+{
+    rtNtPathFreeNative(pNtName, phRootDir);
+}
+
+
+/**
  * Wrapper around NtCreateFile.
  *
  * @returns IPRT status code.
@@ -202,19 +383,19 @@ void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
  * @param   phHandle            Where to return the handle.
  * @param   puAction            Where to return the action taken. Optional.
  */
-int  rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
-                  ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
-                  PHANDLE phHandle, PULONG_PTR puAction)
+RTDECL(int) RTNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
+                         ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
+                         PHANDLE phHandle, PULONG_PTR puAction)
 {
-    *phHandle = MY_INVALID_HANDLE_VALUE;
+    *phHandle = RTNT_INVALID_HANDLE_VALUE;
 
     HANDLE         hRootDir;
     UNICODE_STRING NtName;
     int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
     if (RT_SUCCESS(rc))
     {
-        HANDLE              hFile = MY_INVALID_HANDLE_VALUE;
-        IO_STATUS_BLOCK     Ios   = MY_IO_STATUS_BLOCK_INITIALIZER;
+        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         OBJECT_ATTRIBUTES   ObjAttr;
         InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
 
@@ -262,18 +443,18 @@ int  rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAt
  *                              @c false if we opened an directory file (normal
  *                              directory).
  */
-int  rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
-                     ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
+RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
+                            ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
 {
-    *phHandle = MY_INVALID_HANDLE_VALUE;
+    *phHandle = RTNT_INVALID_HANDLE_VALUE;
 
     HANDLE         hRootDir;
     UNICODE_STRING NtName;
     int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
     if (RT_SUCCESS(rc))
     {
-        HANDLE              hFile = MY_INVALID_HANDLE_VALUE;
-        IO_STATUS_BLOCK     Ios   = MY_IO_STATUS_BLOCK_INITIALIZER;
+        HANDLE              hFile = RTNT_INVALID_HANDLE_VALUE;
+        IO_STATUS_BLOCK     Ios   = RTNT_IO_STATUS_BLOCK_INITIALIZER;
         OBJECT_ATTRIBUTES   ObjAttr;
         InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
 
@@ -346,7 +527,7 @@ int  rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fSha
  * @returns IPRT status code
  * @param   hHandle             The handle value.
  */
-int rtNtPathClose(HANDLE hHandle)
+RTDECL(int) RTNtPathClose(HANDLE hHandle)
 {
     NTSTATUS rcNt = NtClose(hHandle);
     if (NT_SUCCESS(rcNt))
diff --git a/src/VBox/Runtime/r3/posix/path-posix.cpp b/src/VBox/Runtime/r3/posix/path-posix.cpp
index 2b7adf9..6467d07 100644
--- a/src/VBox/Runtime/r3/posix/path-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/path-posix.cpp
@@ -79,224 +79,6 @@ RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPat
 }
 
 
-/**
- * Cleans up a path specifier a little bit.
- * This includes removing duplicate slashes, unnecessary single dots, and
- * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
- *
- * @returns Number of bytes in the clean path.
- * @param   pszPath     The path to cleanup.
- */
-static int fsCleanPath(char *pszPath)
-{
-    /*
-     * Change to '/' and remove duplicates.
-     */
-    char   *pszSrc = pszPath;
-    char   *pszTrg = pszPath;
-#ifdef HAVE_UNC
-    int     fUnc = 0;
-    if (    RTPATH_IS_SLASH(pszPath[0])
-        &&  RTPATH_IS_SLASH(pszPath[1]))
-    {   /* Skip first slash in a unc path. */
-        pszSrc++;
-        *pszTrg++ = '/';
-        fUnc = 1;
-    }
-#endif
-
-    for (;;)
-    {
-        char ch = *pszSrc++;
-        if (RTPATH_IS_SLASH(ch))
-        {
-            *pszTrg++ = '/';
-            for (;;)
-            {
-                do  ch = *pszSrc++;
-                while (RTPATH_IS_SLASH(ch));
-
-                /* Remove '/./' and '/.'. */
-                if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
-                    break;
-            }
-        }
-        *pszTrg = ch;
-        if (!ch)
-            break;
-        pszTrg++;
-    }
-
-    /*
-     * Remove trailing slash if the path may be pointing to a directory.
-     */
-    int cch = pszTrg - pszPath;
-    if (    cch > 1
-        &&  RTPATH_IS_SLASH(pszTrg[-1])
-#ifdef HAVE_DRIVE
-        &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
-#endif
-        &&  !RTPATH_IS_SLASH(pszTrg[-2]))
-        pszPath[--cch] = '\0';
-
-    return cch;
-}
-
-
-RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
-{
-    int rc;
-
-    /*
-     * Validation.
-     */
-    AssertPtr(pszAbsPath);
-    AssertPtr(pszPath);
-    if (RT_UNLIKELY(!*pszPath))
-        return VERR_INVALID_PARAMETER;
-
-    /*
-     * Make a clean working copy of the input.
-     */
-    size_t cchPath = strlen(pszPath);
-    if (cchPath > PATH_MAX)
-    {
-        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
-        return VERR_FILENAME_TOO_LONG;
-    }
-
-    char szTmpPath[PATH_MAX + 1];
-    memcpy(szTmpPath, pszPath, cchPath + 1);
-    size_t cchTmpPath = fsCleanPath(szTmpPath);
-
-    /*
-     * Handle "." specially (fsCleanPath does).
-     */
-    if (szTmpPath[0] == '.' && !szTmpPath[1])
-        return RTPathGetCurrent(pszAbsPath, cchAbsPath);
-
-    /*
-     * Do we have a root slash?
-     */
-    char *pszCur = szTmpPath;
-#ifdef HAVE_DRIVE
-    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
-        pszCur += 3;
-# ifdef HAVE_UNC
-    else if (pszCur[0] == '/' && pszCur[1] == '/')
-        pszCur += 2;
-# endif
-#else  /* !HAVE_DRIVE */
-    if (pszCur[0] == '/')
-        pszCur += 1;
-#endif /* !HAVE_DRIVE */
-    else
-    {
-        /*
-         * No, prepend the current directory to the relative path.
-         */
-        char szCurDir[RTPATH_MAX];
-        rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
-        AssertRCReturn(rc, rc);
-
-        size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
-        if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
-        {
-            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
-            return VERR_FILENAME_TOO_LONG;
-        }
-
-        memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
-        memcpy(szTmpPath, szCurDir, cchCurDir);
-        szTmpPath[cchCurDir] = '/';
-
-
-#ifdef HAVE_DRIVE
-        if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
-            pszCur += 3;
-# ifdef HAVE_UNC
-        else if (pszCur[0] == '/' && pszCur[1] == '/')
-            pszCur += 2;
-# endif
-#else
-        if (pszCur[0] == '/')
-            pszCur += 1;
-#endif
-        else
-            AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
-    }
-
-    char *pszTop = pszCur;
-
-    /*
-     * Get rid of double dot path components by evaluating them.
-     */
-    for (;;)
-    {
-        if (   pszCur[0] == '.'
-            && pszCur[1] == '.'
-            && (!pszCur[2] || pszCur[2] == '/'))
-        {
-            /* rewind to the previous component if any */
-            char *pszPrev = pszCur - 1;
-            if (pszPrev > pszTop)
-                while (*--pszPrev != '/')
-                    ;
-
-            AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
-            memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
-
-            pszCur = pszPrev;
-        }
-        else
-        {
-            /* advance to end of component. */
-            while (*pszCur && *pszCur != '/')
-                pszCur++;
-        }
-
-        if (!*pszCur)
-            break;
-
-        /* skip the slash */
-        ++pszCur;
-    }
-
-    if (pszCur < pszTop)
-    {
-        /*
-         * We overwrote the root slash with '\0', restore it.
-         */
-        *pszCur++ = '/';
-        *pszCur = '\0';
-    }
-    else if (pszCur > pszTop && pszCur[-1] == '/')
-    {
-        /*
-         * Extra trailing slash in a non-root path, remove it.
-         * (A bit questionable...)
-         */
-        *--pszCur = '\0';
-    }
-
-    /*
-     * Copy the result to the user buffer.
-     */
-    cchTmpPath = pszCur - szTmpPath;
-    if (cchTmpPath < cchAbsPath)
-    {
-        memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
-        rc = VINF_SUCCESS;
-    }
-    else
-        rc = VERR_BUFFER_OVERFLOW;
-
-    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
-             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
-    return rc;
-}
-
-
 RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode)
 {
     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
diff --git a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
index 0a08ea9..4a2503a 100644
--- a/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
+++ b/src/VBox/Runtime/r3/win/RTSystemQueryOSInfo-win.cpp
@@ -216,6 +216,7 @@ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t
                 case kRTWinOSType_7:            strcpy(szTmp, "Windows 7"); break;
                 case kRTWinOSType_8:            strcpy(szTmp, "Windows 8"); break;
                 case kRTWinOSType_81:           strcpy(szTmp, "Windows 8.1"); break;
+                case kRTWinOSType_10:           strcpy(szTmp, "Windows 10"); break;
 
                 case kRTWinOSType_NT_UNKNOWN:
                     RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u",
diff --git a/src/VBox/Runtime/r3/win/init-win.cpp b/src/VBox/Runtime/r3/win/init-win.cpp
index 0f00d9b..f58a45f 100644
--- a/src/VBox/Runtime/r3/win/init-win.cpp
+++ b/src/VBox/Runtime/r3/win/init-win.cpp
@@ -160,6 +160,9 @@ static RTWINOSTYPE rtR3InitWinSimplifiedVersion(OSVERSIONINFOEXW const *pOSInfoE
         else if (   dwMajorVersion == 6
                  && dwMinorVersion == 3)
             enmVer = kRTWinOSType_81;
+        else if (   dwMajorVersion == 6
+                 && dwMinorVersion == 4)
+            enmVer = kRTWinOSType_10;
         else
             enmVer = kRTWinOSType_NT_UNKNOWN;
     }
diff --git a/src/VBox/Runtime/r3/win/internal-r3-win.h b/src/VBox/Runtime/r3/win/internal-r3-win.h
index fdbd932..cc73b58 100644
--- a/src/VBox/Runtime/r3/win/internal-r3-win.h
+++ b/src/VBox/Runtime/r3/win/internal-r3-win.h
@@ -40,6 +40,7 @@ typedef enum RTWINOSTYPE
     kRTWinOSType_7,
     kRTWinOSType_8,
     kRTWinOSType_81,
+    kRTWinOSType_10,
     kRTWinOSType_NT_UNKNOWN = 199,
     kRTWinOSType_NT_LAST    = kRTWinOSType_UNKNOWN
 } RTWINOSTYPE;
diff --git a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
index 1f6c654..dc78228 100644
--- a/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
+++ b/src/VBox/Runtime/r3/win/ntdll-mini-implib.def
@@ -32,9 +32,12 @@ EXPORTS
     CsrClientCallServer                   ;;= _CsrClientCallServer at 16
 
     NtAllocateVirtualMemory               ;;= _NtAllocateVirtualMemory at 24
+    NtClearEvent                          ;;= _NtClearEvent at 4
     NtClose                               ;;= _NtClose at 4
+    NtCreateEvent                         ;;= _NtCreateEvent at 20
     NtCreateFile                          ;;= _NtCreateFile at 44
     NtCreateSection                       ;;= _NtCreateSection at 28
+    NtCreateSymbolicLinkObject            ;;= _NtCreateSymbolicLinkObject at 16
     NtDelayExecution                      ;;= _NtDelayExecution at 8
     NtDeviceIoControlFile                 ;;= _NtDeviceIoControlFile at 40
     NtDuplicateObject                     ;;= _NtDuplicateObject at 28
@@ -42,29 +45,36 @@ EXPORTS
     NtGetContextThread                    ;;= _NtGetContextThread at 8
     NtMapViewOfSection                    ;;= _NtMapViewOfSection at 40
     NtOpenDirectoryObject                 ;;= _NtOpenDirectoryObject at 12
+    NtOpenEvent                           ;;= _NtOpenEvent at 12
     NtOpenKey                             ;;= _NtOpenKey at 12
     NtOpenProcess                         ;;= _NtOpenProcess at 16
     NtOpenProcessToken                    ;;= _NtOpenProcessToken at 12
+    NtOpenSymbolicLinkObject              ;;= _NtOpenSymbolicLinkObject at 12
     NtOpenThread                          ;;= _NtOpenThread at 16
     NtOpenThreadToken                     ;;= _NtOpenThreadToken at 16
     NtProtectVirtualMemory                ;;= _NtProtectVirtualMemory at 20
     NtQueryDirectoryFile                  ;;= _NtQueryDirectoryFile at 44
     NtQueryDirectoryObject                ;;= _NtQueryDirectoryObject at 28
+    NtQueryEvent                          ;;= _NtQueryEvent at 20
     NtQueryInformationFile                ;;= _NtQueryInformationFile at 20
     NtQueryInformationProcess             ;;= _NtQueryInformationProcess at 20
     NtQueryInformationThread              ;;= _NtQueryInformationThread at 20
     NtQueryInformationToken               ;;= _NtQueryInformationToken at 20
     NtQueryObject                         ;;= _NtQueryObject at 20
     NtQuerySecurityObject                 ;;= _NtQuerySecurityObject at 20
+    NtQuerySymbolicLinkObject             ;;= _NtQuerySymbolicLinkObject at 12
+    NtQuerySystemInformation              ;;= _NtQuerySystemInformation at 16
     NtQueryTimerResolution                ;;= _NtQueryTimerResolution at 12
     NtQueryValueKey                       ;;= _NtQueryValueKey at 24
     NtQueryVirtualMemory                  ;;= _NtQueryVirtualMemory at 24
     NtQueryVolumeInformationFile          ;;= _NtQueryVolumeInformationFile at 20
     NtReadFile                            ;;= _NtReadFile at 36
     NtReadVirtualMemory                   ;;= _NtReadVirtualMemory at 20
+    NtResetEvent                          ;;= _NtResetEvent at 8
     NtResumeProcess                       ;;= _NtResumeProcess at 4
     NtResumeThread                        ;;= _NtResumeThread at 8
     NtSetContextThread                    ;;= _NtSetContextThread at 8
+    NtSetEvent                            ;;= _NtSetEvent at 8
     NtSetInformationFile                  ;;= _NtSetInformationFile at 20
     NtSetInformationObject                ;;= _NtSetInformationObject at 16
     NtSetInformationProcess               ;;= _NtSetInformationProcess at 16
@@ -75,18 +85,22 @@ EXPORTS
     NtTerminateProcess                    ;;= _NtTerminateProcess at 8
     NtTerminateThread                     ;;= _NtTerminateThread at 8
     NtUnmapViewOfSection                  ;;= _NtUnmapViewOfSection at 8
-    NtWaitForSingleObject                 ;;= _NtWaitForSingleObject at 12
     NtWaitForMultipleObjects              ;;= _NtWaitForMultipleObjects at 20
+    NtWaitForSingleObject                 ;;= _NtWaitForSingleObject at 12
     NtWriteFile                           ;;= _NtWriteFile at 36
     NtWriteVirtualMemory                  ;;= _NtWriteVirtualMemory at 20
     NtYieldExecution                      ;;= _NtYieldExecution at 0
 
     LdrInitializeThunk                    ;;= _LdrInitializeThunk at 12
+    LdrRegisterDllNotification            ;;= _LdrRegisterDllNotification at 16
 
     RtlAddAccessAllowedAce                ;;= _RtlAddAccessAllowedAce at 16
     RtlAddAccessDeniedAce                 ;;= _RtlAddAccessDeniedAce at 16
+    RtlAllocateHeap                       ;;= _RtlAllocateHeap at 12
+    RtlCompactHeap                        ;;= _RtlCompactHeap at 8
     RtlCopySid                            ;;= _RtlCopySid at 12
     RtlCreateAcl                          ;;= _RtlCreateAcl at 12
+    RtlCreateHeap                         ;;= _RtlCreateHeap at 24
     RtlCreateProcessParameters            ;;= _RtlCreateProcessParameters at 40
     RtlCreateSecurityDescriptor           ;;= _RtlCreateSecurityDescriptor at 8
     RtlCreateUserProcess                  ;;= _RtlCreateUserProcess at 40
@@ -94,12 +108,21 @@ EXPORTS
     RtlDestroyProcessParameters           ;;= _RtlDestroyProcessParameters at 4
     RtlDosApplyFileIsolationRedirection_Ustr ;;= _RtlDosApplyFileIsolationRedirection_Ustr at 36
     RtlEqualSid                           ;;= _RtlEqualSid at 8
+    RtlExitUserProcess                    ;;= _RtlExitUserProcess at 4
+    RtlExitUserThread                     ;;= _RtlExitUserThread at 4
     RtlExpandEnvironmentStrings_U         ;;= _RtlExpandEnvironmentStrings_U at 16
+    RtlFreeHeap                           ;;= _RtlFreeHeap at 12
     RtlFreeUnicodeString                  ;;= _RtlFreeUnicodeString at 4
+    RtlGetLastNtStatus                    ;;= _RtlGetLastNtStatus at 0
+    RtlGetLastWin32Error                  ;;= _RtlGetLastWin32Error at 0
     RtlGetVersion                         ;;= _RtlGetVersion at 4
     RtlInitializeSid                      ;;= _RtlInitializeSid at 12
     RtlNtStatusToDosError                 ;;= _RtlNtStatusToDosError at 4
+    RtlReAllocateHeap                     ;;= _RtlReAllocateHeap at 16
+    RtlRestoreLastWin32Error              ;;= _RtlRestoreLastWin32Error at 4
     RtlSetDaclSecurityDescriptor          ;;= _RtlSetDaclSecurityDescriptor at 16
+    RtlSetLastWin32Error                  ;;= _RtlSetLastWin32Error at 4
+    RtlSetLastWin32ErrorAndNtStatusFromNtStatus ;;= _RtlSetLastWin32ErrorAndNtStatusFromNtStatus at 4
+    RtlSizeHeap                           ;;= _RtlSizeHeap at 12
     RtlSubAuthoritySid                    ;;= _RtlSubAuthoritySid at 8
 
-
diff --git a/src/VBox/Runtime/r3/win/path-win.cpp b/src/VBox/Runtime/r3/win/path-win.cpp
index 0245b77..7d5b055 100644
--- a/src/VBox/Runtime/r3/win/path-win.cpp
+++ b/src/VBox/Runtime/r3/win/path-win.cpp
@@ -88,7 +88,7 @@ RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPat
     return rc;
 }
 
-
+#if 0
 /**
  * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
  *
@@ -124,6 +124,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
         rc = RTUtf16ToUtf8Ex(&wsz[0], RTSTR_MAX, &pszAbsPath, cchAbsPath, &cch);
         if (RT_SUCCESS(rc))
         {
+# if 1 /** @todo This code is completely bonkers. */
             /*
              * Remove trailing slash if the path may be pointing to a directory.
              * (See posix variant.)
@@ -133,6 +134,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
                 &&  !RTPATH_IS_VOLSEP(pszAbsPath[cch - 2])
                 &&  !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
                 pszAbsPath[cch - 1] = '\0';
+# endif
         }
     }
     else if (rc <= 0)
@@ -143,6 +145,7 @@ RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
     RTUtf16Free(pwszPath);
     return rc;
 }
+#endif
 
 
 /**
@@ -683,3 +686,20 @@ RTDECL(int) RTPathSetCurrent(const char *pszPath)
     return rc;
 }
 
+
+RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
+{
+    WCHAR wszInput[4];
+    wszInput[0] = chDrive;
+    wszInput[1] = ':';
+    wszInput[2] = '\0';
+
+    int rc;
+    RTUTF16 wszFullPath[RTPATH_MAX];
+    if (GetFullPathNameW(wszInput, RTPATH_MAX, wszFullPath, NULL))
+        rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
+    else
+        rc = RTErrConvertFromWin32(GetLastError());
+    return rc;
+}
+
diff --git a/src/VBox/Runtime/testcase/tstRTPath.cpp b/src/VBox/Runtime/testcase/tstRTPath.cpp
index 131466a..5986708 100644
--- a/src/VBox/Runtime/testcase/tstRTPath.cpp
+++ b/src/VBox/Runtime/testcase/tstRTPath.cpp
@@ -314,7 +314,7 @@ int main()
     { "C:\\MustDie", "\\from_root/dir/..", VINF_SUCCESS, "C:\\from_root" },
     { "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" },
     { NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ },
-    { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server" },
+    { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" },
     { NULL, "\\\\", VINF_SUCCESS, "\\\\" },
     { NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ },
     { "\\\\server\\share_as_base", "/from_root", VINF_SUCCESS, "\\\\server\\from_root" },
diff --git a/src/VBox/Storage/VHD.cpp b/src/VBox/Storage/VHD.cpp
index 229498b..1f9db9f 100644
--- a/src/VBox/Storage/VHD.cpp
+++ b/src/VBox/Storage/VHD.cpp
@@ -2694,7 +2694,7 @@ static int vhdResize(void *pBackendData, uint64_t cbSize,
         {
             if (pImage->pBlockAllocationTable[idxBlock] != ~0U)
             {
-                uint64_t offStartBlock = pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE;
+                uint64_t offStartBlock = (uint64_t)pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE;
                 if (offStartBlock < offStartDataOld)
                     offStartDataOld = offStartBlock;
                 cBlocksAllocated++;
diff --git a/src/VBox/Storage/testcase/BuiltinTests.h b/src/VBox/Storage/testcase/BuiltinTests.h
new file mode 100644
index 0000000..072ff41
--- /dev/null
+++ b/src/VBox/Storage/testcase/BuiltinTests.h
@@ -0,0 +1,41 @@
+/** @file
+ *
+ * tstVDIo testing utility - builtin tests.
+ */
+
+/*
+ * Copyright (C) 2014 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.
+ */
+#ifndef _BuiltinTests_h__
+#define _BuiltinTests_h__
+
+/**
+ * Builtin Tests (in generated BuiltinTests.cpp)
+ */
+typedef struct TSTVDIOTESTENTRY
+{
+    /** Pointer to the raw bytes. */
+    const unsigned char    *pch;
+    /** Number of bytes. */
+    unsigned                cb;
+} TSTVDIOTESTENTRY;
+/** Pointer to a trust anchor table entry. */
+typedef TSTVDIOTESTENTRY const *PCTSTVDIOTESTENTRY;
+
+/** Macro for simplifying generating the trust anchor tables. */
+#define TSTVDIOTESTENTRY_GEN(a_abTest)      { &a_abTest[0], sizeof(a_abTest) }
+
+/** All tests we know. */
+extern TSTVDIOTESTENTRY const       g_aVDIoTests[];
+/** Number of entries in g_aVDIoTests. */
+extern unsigned const               g_cVDIoTests;
+
+#endif /* _BuiltinTests_h__ */
diff --git a/src/VBox/Storage/testcase/Makefile.kmk b/src/VBox/Storage/testcase/Makefile.kmk
index 9d44e45..5098ee5 100644
--- a/src/VBox/Storage/testcase/Makefile.kmk
+++ b/src/VBox/Storage/testcase/Makefile.kmk
@@ -47,21 +47,71 @@ ifdef VBOX_WITH_TESTCASES
  tstVDCopy_SOURCES  = tstVDCopy.cpp
  tstVDCopy_LIBS = $(LIB_DDU)
 
- ifn1of ($(KBUILD_TARGET),win)
-  PROGRAMS += tstVDIo
-
-  tstVDIo_TEMPLATE = VBOXR3TSTEXE
-  tstVDIo_SOURCES  = tstVDIo.cpp \
-  	VDIoBackend.cpp \
-  	VDIoBackendMem.cpp \
-  	VDMemDisk.cpp \
-  	VDIoRnd.cpp \
-  	VDScript.cpp \
-  	VDScriptAst.cpp \
-  	VDScriptChecker.cpp \
-  	VDScriptInterp.cpp
-  tstVDIo_LIBS = \
-  	$(LIB_DDU) \
+ PROGRAMS += tstVDIo
+
+ #
+ # VD I/O test scripts to built in -> .cpp
+ #
+ TSTVDIO_BUILTIN_TESTS_FILE = $(tstVDIo_0_OUTDIR)/BuiltinTests.cpp
+ TSTVDIO_BUILTIN_TESTS := \
+        tstVDIo=tstVDIo.vd \
+        tstVDResize=tstVDResize.vd \
+        tstVDCompact=tstVDCompact.vd \
+        tstVDCopy=tstVDCopy.vd \
+        tstVDDiscard=tstVDDiscard.vd \
+        tstVDShareable=tstVDShareable.vd
+ TSTVDIO_BUILTIN_TEST_NAMES := $(foreach test,$(TSTVDIO_BUILTIN_TESTS),$(firstword $(subst =,$(SPACE) ,$(test))))
+ TSTVDIO_PATH_TESTS := $(PATH_SUB_CURRENT)
+
+ # 1=name, 2=filter
+ TSTVDIO_GEN_TEST_MACRO = 'TSTVDIOTESTENTRY const g_a$(1)[] =' '{' \
+	$(foreach testnm,$(filter $(2),$(TSTVDIO_BUILTIN_TEST_NAMES)), '    TSTVDIOTESTENTRY_GEN(g_ab$(testnm)),') \
+	'};' 'unsigned const g_c$(1) = RT_ELEMENTS(g_a$(1));' '' ''
+
+ $$(TSTVDIO_BUILTIN_TESTS_FILE): $(MAKEFILE_CURRENT) \
+		$(foreach test,$(TSTVDIO_BUILTIN_TESTS),$(TSTVDIO_PATH_TESTS)/$(lastword $(subst =,$(SPACE) ,$(test)))) \
+		$(VBOX_BIN2C) \
+		| $$(dir $$@)
+	$(QUIET)$(RM) -f -- $@ $@.vd
+	$(QUIET)$(APPEND) -n "$@" \
+      	'' \
+      	'#include "BuiltinTests.h"' \
+               ''
+	$(foreach test,$(TSTVDIO_BUILTIN_TESTS), $(NLTAB)$(VBOX_BIN2C) -ascii --append \
+		"$(firstword $(subst =,$(SP) ,$(test)))" \
+		"$(TSTVDIO_PATH_TESTS)/$(lastword $(subst =,$(SP) ,$(test)))" \
+		"$@")
+
+# Generate test lists.
+	$(QUIET)$(APPEND) -n "$@" '' \
+               $(call TSTVDIO_GEN_TEST_MACRO,VDIoTests,%) \
+
+ ifn1of ($(KBUILD_TARGET), win)
+  VBOX_TSTVDIO_WITH_LOG_REPLAY = 1
+ endif
+
+ tstVDIo_TEMPLATE = VBOXR3TSTEXE
+ tstVDIo_INCS := $(PATH_SUB_CURRENT)
+
+ ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+  tstVDIo_DEFS += VBOX_TSTVDIO_WITH_LOG_REPLAY
+ endif
+
+ tstVDIo_SOURCES  = tstVDIo.cpp \
+ 	VDIoBackend.cpp \
+ 	VDIoBackendMem.cpp \
+ 	VDMemDisk.cpp \
+ 	VDIoRnd.cpp \
+ 	VDScript.cpp \
+ 	VDScriptAst.cpp \
+ 	VDScriptChecker.cpp \
+ 	VDScriptInterp.cpp \
+ 	$(TSTVDIO_BUILTIN_TESTS_FILE)
+ tstVDIo_LIBS = \
+ 	$(LIB_DDU)
+
+ ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+  tstVDIo_LIBS += \
   	$(PATH_STAGE_LIB)/StorageDbgLib$(VBOX_SUFF_LIB)
  endif
 
diff --git a/src/VBox/Storage/testcase/VDMemDisk.cpp b/src/VBox/Storage/testcase/VDMemDisk.cpp
index a921250..e953657 100644
--- a/src/VBox/Storage/testcase/VDMemDisk.cpp
+++ b/src/VBox/Storage/testcase/VDMemDisk.cpp
@@ -89,6 +89,7 @@ void VDMemDiskDestroy(PVDMEMDISK pMemDisk)
     AssertPtrReturnVoid(pMemDisk);
 
     RTAvlrU64Destroy(pMemDisk->pTreeSegments, vdMemDiskDestroy, NULL);
+    RTMemFree(pMemDisk->pTreeSegments);
     RTMemFree(pMemDisk);
 }
 
diff --git a/src/VBox/Storage/testcase/VDScript.cpp b/src/VBox/Storage/testcase/VDScript.cpp
index 6378631..9b6ef83 100644
--- a/src/VBox/Storage/testcase/VDScript.cpp
+++ b/src/VBox/Storage/testcase/VDScript.cpp
@@ -88,15 +88,24 @@ typedef enum VDSCRIPTTOKENKEYWORD
 {
     VDSCRIPTTOKENKEYWORD_INVALID = 0,
     VDSCRIPTTOKENKEYWORD_CONTINUE,
+    VDSCRIPTTOKENKEYWORD_REGISTER,
+    VDSCRIPTTOKENKEYWORD_RESTRICT,
+    VDSCRIPTTOKENKEYWORD_VOLATILE,
+    VDSCRIPTTOKENKEYWORD_TYPEDEF,
     VDSCRIPTTOKENKEYWORD_DEFAULT,
+    VDSCRIPTTOKENKEYWORD_EXTERN,
+    VDSCRIPTTOKENKEYWORD_STATIC,
     VDSCRIPTTOKENKEYWORD_RETURN,
     VDSCRIPTTOKENKEYWORD_SWITCH,
+    VDSCRIPTTOKENKEYWORD_STRUCT,
     VDSCRIPTTOKENKEYWORD_WHILE,
     VDSCRIPTTOKENKEYWORD_BREAK,
+    VDSCRIPTTOKENKEYWORD_CONST,
     VDSCRIPTTOKENKEYWORD_FALSE,
     VDSCRIPTTOKENKEYWORD_TRUE,
     VDSCRIPTTOKENKEYWORD_ELSE,
     VDSCRIPTTOKENKEYWORD_CASE,
+    VDSCRIPTTOKENKEYWORD_AUTO,
     VDSCRIPTTOKENKEYWORD_FOR,
     VDSCRIPTTOKENKEYWORD_IF,
     VDSCRIPTTOKENKEYWORD_DO,
@@ -219,6 +228,7 @@ static VDSCRIPTOP g_aScriptOps[] =
     {"!=",  2},
     {">=",  2},
     {"<=",  2},
+    {"->",  2},
     {"=",   1},
     {"+",   1},
     {"-",   1},
@@ -231,7 +241,8 @@ static VDSCRIPTOP g_aScriptOps[] =
     {"<",   1},
     {">",   1},
     {"!",   1},
-    {"~",   1}
+    {"~",   1},
+    {".",   1}
 };
 
 /**
@@ -268,15 +279,24 @@ typedef VDSCRIPTKEYWORD *PVDSCRIPTKEYWORD;
 static VDSCRIPTKEYWORD g_aKeywords[] =
 {
     {"continue", 8, VDSCRIPTTOKENKEYWORD_CONTINUE},
+    {"register", 8, VDSCRIPTTOKENKEYWORD_REGISTER},
+    {"restrict", 8, VDSCRIPTTOKENKEYWORD_RESTRICT},
+    {"voaltile", 8, VDSCRIPTTOKENKEYWORD_VOLATILE},
+    {"typedef",  7, VDSCRIPTTOKENKEYWORD_TYPEDEF},
     {"default",  7, VDSCRIPTTOKENKEYWORD_DEFAULT},
+    {"extern",   6, VDSCRIPTTOKENKEYWORD_EXTERN},
+    {"static",   6, VDSCRIPTTOKENKEYWORD_STATIC},
     {"return",   6, VDSCRIPTTOKENKEYWORD_RETURN},
     {"switch",   6, VDSCRIPTTOKENKEYWORD_SWITCH},
+    {"struct",   6, VDSCRIPTTOKENKEYWORD_STRUCT},
     {"while",    5, VDSCRIPTTOKENKEYWORD_WHILE},
     {"break",    5, VDSCRIPTTOKENKEYWORD_BREAK},
+    {"const",    5, VDSCRIPTTOKENKEYWORD_CONST},
     {"false",    5, VDSCRIPTTOKENKEYWORD_FALSE},
     {"true",     4, VDSCRIPTTOKENKEYWORD_TRUE},
     {"else",     4, VDSCRIPTTOKENKEYWORD_ELSE},
     {"case",     4, VDSCRIPTTOKENKEYWORD_CASE},
+    {"auto",     4, VDSCRIPTTOKENKEYWORD_AUTO},
     {"for",      3, VDSCRIPTTOKENKEYWORD_FOR},
     {"if",       2, VDSCRIPTTOKENKEYWORD_IF},
     {"do",       2, VDSCRIPTTOKENKEYWORD_DO}
@@ -286,6 +306,8 @@ static int vdScriptParseCompoundStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTM
 static int vdScriptParseStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeStmt);
 static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
 static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
+static int vdScriptParseCastExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
+static int vdScriptParseConstExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
 
 /**
  * Returns whether the tokenizer reached the end of the stream.
@@ -521,6 +543,11 @@ static void vdScriptTokenizerGetNumberConst(PVDTOKENIZER pTokenizer, PVDSCRIPTTO
         pToken->Class.NumConst.u64 *= _1G;
         vdScriptTokenizerSkipCh(pTokenizer);
     }
+    else if (vdScriptTokenizerGetCh(pTokenizer) == 'T')
+    {
+        pToken->Class.NumConst.u64 *= _1T;
+        vdScriptTokenizerSkipCh(pTokenizer);
+    }
 }
 
 /**
@@ -1031,6 +1058,11 @@ static int vdScriptParseFnCallArgumentList(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEX
  *          postfix-expression ( argument-expression )
  *          postfix-expression ++
  *          postfix-expression --
+ *          postfix-expression .  identifier
+ *          postfix-expression -> identifier
+ * @note: Not supported so far are:
+ *          ( type-name ) { initializer-list }
+ *          ( type-name ) { initializer-list , }
  */
 static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
 {
@@ -1070,6 +1102,46 @@ static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXP
                 else
                     rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
             }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "->"))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                {
+                    PVDSCRIPTASTIDE pIde = NULL;
+                    rc = vdScriptParseIde(pThis, &pIde);
+                    if (RT_SUCCESS(rc))
+                    {
+                        pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE;
+                        pExprNew->Deref.pIde = pIde;
+                        pExprNew->Deref.pExpr = pExpr;
+                        pExpr = pExprNew;
+                    }
+                    else
+                        vdScriptAstNodeFree(&pExprNew->Core);
+                }
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
+            else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "."))
+            {
+                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+                if (pExprNew)
+                {
+                    PVDSCRIPTASTIDE pIde = NULL;
+                    rc = vdScriptParseIde(pThis, &pIde);
+                    if (RT_SUCCESS(rc))
+                    {
+                        pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DOT;
+                        pExprNew->Deref.pIde = pIde;
+                        pExprNew->Deref.pExpr = pExpr;
+                        pExpr = pExprNew;
+                    }
+                    else
+                        vdScriptAstNodeFree(&pExprNew->Core);
+                }
+                else
+                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            }
             else if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
             {
                 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
@@ -1114,10 +1186,12 @@ static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXP
  *          postfix-expression
  *          ++ unary-expression
  *          -- unary-expression
- *          + unary-expression
- *          - unary-expression
- *          ~ unary-expression
- *          ! unary-expression
+ *          + cast-expression
+ *          - cast-expression
+ *          ~ cast-expression
+ *          ! cast-expression
+ *          & cast-expression
+ *          * cast-expression
  */
 static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
 {
@@ -1127,58 +1201,69 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
 
     LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
 
+    /** @todo: Think about a more beautiful way of parsing this. */
     while (true)
     {
         bool fQuit = false;
+        bool fCastExprFollows = false;
         PVDSCRIPTASTEXPR pExprNew = NULL;
+        VDSCRIPTEXPRTYPE enmType = VDSCRIPTEXPRTYPE_INVALID;
 
         if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
-        {
-            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-            if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
-            else
-                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
-        }
+            enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
         else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
-        {
-            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-            if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
-            else
-                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
-        }
+            enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
         else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
         {
-            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-            if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
-            else
-                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
+            fCastExprFollows = true;
         }
         else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
         {
-            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-            if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
-            else
-                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
+            fCastExprFollows = true;
         }
         else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "~"))
         {
-            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-            if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
-            else
-                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+            enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
+            fCastExprFollows = true;
         }
         else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!"))
         {
+            enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
+            fCastExprFollows = true;
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&"))
+        {
+            enmType = VDSCRIPTEXPRTYPE_UNARY_REFERENCE;
+            fCastExprFollows = true;
+        }
+        else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
+        {
+            enmType = VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE;
+            fCastExprFollows = true;
+        }
+
+        if (enmType != VDSCRIPTEXPRTYPE_INVALID)
+        {
             pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
             if (pExprNew)
-                pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
+                pExprNew->enmType = enmType;
             else
                 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+
+            if (   RT_SUCCESS(rc)
+                && fCastExprFollows)
+            {
+                PVDSCRIPTASTEXPR pCastExpr = NULL;
+
+                rc = vdScriptParseCastExpression(pThis, &pCastExpr);
+                if (RT_SUCCESS(rc))
+                    pExprNew->pExpr = pCastExpr;
+                else
+                    vdScriptAstNodeFree(&pExprNew->Core);
+                fQuit = true;
+            }
         }
         else
         {
@@ -1216,6 +1301,168 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
 }
 
 /**
+ * Parse a storage class specifier.
+ *
+ * @returns nothing.
+ * @param   pThis                The script context.
+ * @param   penmStorageClass     Where to return the parsed storage classe.
+ *                               Contains VDSCRIPTASTSTORAGECLASS_INVALID if no
+ *                               valid storage class specifier was found.
+ *
+ * @note Syntax:
+ *      typedef
+ *      extern
+ *      static
+ *      auto
+ *      register
+ */
+static void vdScriptParseStorageClassSpecifier(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTORAGECLASS penmStorageClass)
+{
+    *penmStorageClass = VDSCRIPTASTSTORAGECLASS_INVALID;
+
+    if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_TYPEDEF))
+        *penmStorageClass = VDSCRIPTASTSTORAGECLASS_TYPEDEF;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_EXTERN))
+        *penmStorageClass = VDSCRIPTASTSTORAGECLASS_EXTERN;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_STATIC))
+        *penmStorageClass = VDSCRIPTASTSTORAGECLASS_STATIC;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_AUTO))
+        *penmStorageClass = VDSCRIPTASTSTORAGECLASS_AUTO;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_REGISTER))
+        *penmStorageClass = VDSCRIPTASTSTORAGECLASS_REGISTER;
+}
+
+/**
+ * Parse a type qualifier.
+ *
+ * @returns nothing.
+ * @param   pThis                The script context.
+ * @param   penmTypeQualifier    Where to return the parsed type qualifier.
+ *                               Contains VDSCRIPTASTTYPEQUALIFIER_INVALID if no
+ *                               valid type qualifier was found.
+ *
+ * @note Syntax:
+ *      const
+ *      restrict
+ *      volatile
+ */
+static void vdScriptParseTypeQualifier(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTTYPEQUALIFIER penmTypeQualifier)
+{
+    *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_INVALID;
+
+    if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_CONST))
+        *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_CONST;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_RESTRICT))
+        *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_RESTRICT;
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_VOLATILE))
+        *penmTypeQualifier = VDSCRIPTASTTYPEQUALIFIER_VOLATILE;
+}
+
+#if 0
+/**
+ * Parse a struct or union specifier.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstTypeSpec        Where to store the type specifier AST node on success.
+ * @param   enmTypeSpecifier     The type specifier to identify whete this is a struct or a union.
+ */
+static int vdScriptParseStructOrUnionSpecifier(PVDSCRIPTCTXINT pThis, , enmTypeSpecifier)
+{
+    int rc = VINF_SUCCESS;
+
+    return rc;
+}
+
+/**
+ * Parse a type specifier.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstTypeSpec        Where to store the type specifier AST node on success.
+ *
+ * @note Syntax:
+ *      struct-or-union-specifier
+ *      enum-specifier
+ *      typedef-name (identifier: includes void, bool, uint8_t, int8_t, ... for basic integer types)
+ */
+static int vdScriptParseTypeSpecifier(PVDSCRIPTCTXINT pThis, )
+{
+    int rc = VINF_SUCCESS;
+
+    if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_STRUCT))
+        rc = vdScriptParseStructOrUnionSpecifier(pThis, , VDSCRIPTASTTYPESPECIFIER_STRUCT);
+    else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_UNION))
+        rc = vdScriptParseStructOrUnionSpecifier(pThis, , VDSCRIPTASTTYPESPECIFIER_UNION);
+    else
+    {
+        PVDSCRIPTASTIDE pIde = NULL;
+
+        rc = vdScriptParseIde(pThis, &pIde);
+        if (RT_SUCCESS(rc))
+        {
+            AssertMsgFailed(("TODO\n")); /* Parse identifier. */
+        }
+    }
+
+    return rc;
+}
+#endif
+
+/**
+ * Parse a cast expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      cast-expression:
+ *          unary-expression
+ *          ( type-name ) cast-expression
+ */
+static int vdScriptParseCastExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    int rc = VINF_SUCCESS;
+    PVDSCRIPTASTEXPR pExpr = NULL;
+
+    LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
+
+#if 0
+    if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
+    {
+        PVDSCRIPTASTTYPE pTypeName = NULL;
+        rc = vdScriptParseTypeName(pThis, &pTypeName);
+        if (   RT_SUCCESS(rc)
+            && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
+        {
+            PVDSCRIPTASTEXPR pExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExpr)
+            {
+                pExpr->enmType = VDSCRIPTEXPRTYPE_CAST;
+                rc = vdScriptParseCastExpression(pThis, &pExpr->Cast.pExpr); /** @todo: Kill recursion. */
+                if (RT_SUCCESS(rc))
+                    pExpr->Cast.pTypeName = pTypeName;
+                else
+                    vdScriptAstNodeFree(&pExpr->Core);
+            }
+            else
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
+
+            if (RT_FAILURE(rc))
+                vdScriptAstNodeFree(&pTypeName->Core);
+        }
+        else if (RT_SUCCESS(rc))
+            rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
+    }
+    else
+#endif
+        rc = vdScriptParseUnaryExpression(pThis, ppAstNodeExpr);
+
+    return rc;
+}
+
+/**
  * Parse a multiplicative expression.
  *
  * @returns VBox status code.
@@ -1224,10 +1471,10 @@ static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR
  *
  * @note Syntax:
  *      multiplicative-expression:
- *          unary-expression
- *          multiplicative-expression * unary-expression
- *          multiplicative-expression / unary-expression
- *          multiplicative-expression % unary-expression
+ *          cast-expression
+ *          multiplicative-expression * cast-expression
+ *          multiplicative-expression / cast-expression
+ *          multiplicative-expression % cast-expression
  */
 static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
 {
@@ -1236,42 +1483,35 @@ static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIP
 
     LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
 
-    rc = vdScriptParseUnaryExpression(pThis, &pExpr);
+    rc = vdScriptParseCastExpression(pThis, &pExpr);
     if (RT_SUCCESS(rc))
     {
-        PVDSCRIPTASTEXPR pExprNew = NULL;
         while (RT_SUCCESS(rc))
         {
+            VDSCRIPTEXPRTYPE enmType = VDSCRIPTEXPRTYPE_INVALID;
+            PVDSCRIPTASTEXPR pExprNew = NULL;
+
             if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
-            {
-                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-                if (pExprNew)
-                    pExprNew->enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
-                else
-                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
-            }
+                enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
             else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/"))
-            {
-                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-                if (pExprNew)
-                    pExprNew->enmType = VDSCRIPTEXPRTYPE_DIVISION;
-                else
-                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
-            }
+                enmType = VDSCRIPTEXPRTYPE_DIVISION;
             else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%"))
-            {
-                pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
-                if (pExprNew)
-                    pExprNew->enmType = VDSCRIPTEXPRTYPE_MODULUS;
-                else
-                    rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
-            }
+                enmType = VDSCRIPTEXPRTYPE_MODULUS;
+            else
+                break;
+
+            pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
+            if (pExprNew)
+                pExprNew->enmType = enmType;
             else
+            {
+                rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
                 break;
+            }
 
             pExprNew->BinaryOp.pLeftExpr = pExpr;
             pExpr = pExprNew;
-            rc = vdScriptParseUnaryExpression(pThis, &pExprNew);
+            rc = vdScriptParseCastExpression(pThis, &pExprNew);
             if (RT_SUCCESS(rc))
                 pExpr->BinaryOp.pRightExpr = pExprNew;
         }
@@ -1818,6 +2058,22 @@ static int vdScriptParseCondExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *
 }
 
 /**
+ * Parse a constant expression.
+ *
+ * @returns VBox status code.
+ * @param   pThis                The script context.
+ * @param   ppAstNodeExpr        Where to store the expression AST node on success.
+ *
+ * @note Syntax:
+ *      constant-expression:
+ *          conditional-expression
+ */
+static int vdScriptParseConstExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
+{
+    return vdScriptParseCondExpression(pThis, ppAstNodeExpr);
+}
+
+/**
  * Parse an assignment expression.
  *
  * @returns VBox status code.
@@ -2644,7 +2900,16 @@ DECLHIDDEN(void) VDScriptCtxDestroy(VDSCRIPTCTX hScriptCtx)
 
     RTStrSpaceDestroy(&pThis->hStrSpaceFn, vdScriptCtxDestroyFnSpace, NULL);
 
-    /** @todo: Go through the list and destroy all ASTs. */
+    /* Go through list of function ASTs and destroy them. */
+    PVDSCRIPTASTCORE pIter;
+    PVDSCRIPTASTCORE pIterNext;
+    RTListForEachSafe(&pThis->ListAst, pIter, pIterNext, VDSCRIPTASTCORE, ListNode)
+    {
+        RTListNodeRemove(&pIter->ListNode);
+        RTListInit(&pIter->ListNode);
+        vdScriptAstNodeFree(pIter);
+    }
+
     RTMemFree(pThis);
 }
 
diff --git a/src/VBox/Storage/testcase/VDScript.h b/src/VBox/Storage/testcase/VDScript.h
index f1731df..93d6455 100644
--- a/src/VBox/Storage/testcase/VDScript.h
+++ b/src/VBox/Storage/testcase/VDScript.h
@@ -42,6 +42,7 @@ typedef enum VDSCRIPTTYPE
     VDSCRIPTTYPE_INT64,
     VDSCRIPTTYPE_STRING,
     VDSCRIPTTYPE_BOOL,
+    VDSCRIPTTYPE_POINTER,
     /** As usual, the 32bit blowup hack. */
     VDSCRIPTTYPE_32BIT_HACK = 0x7fffffff
 } VDSCRIPTTYPE;
@@ -70,6 +71,7 @@ typedef struct VDSCRIPTARG
         int64_t     i64;
         const char *psz;
         bool        f;
+        void       *p;
     };
 } VDSCRIPTARG;
 /** Pointer to an argument. */
@@ -102,6 +104,43 @@ typedef VDSCRIPTCALLBACK *PVDSCRIPTCALLBACK;
 typedef const VDSCRIPTCALLBACK *PCVDSCRIPTCALLBACK;
 
 /**
+ * @{
+ */
+/** The address space stays assigned to a variable
+ * even if the pointer is casted to another type.
+ */
+#define VDSCRIPT_AS_FLAGS_TRANSITIVE RT_BIT(0)
+/** @} */
+
+/**
+ * Address space read callback
+ *
+ * @returns VBox status code.
+ * @param   pvUser         Opaque user data given on registration.
+ * @param   Address        The address to read from, address is stored in the member for
+ *                         base type given on registration.
+ * @param   pvBuf          Where to store the read bits.
+ * @param   cbRead         How much to read.
+ */
+typedef DECLCALLBACK(int) FNVDSCRIPTASREAD(void *pvUser, VDSCRIPTARG Address, void *pvBuf, size_t cbRead);
+/** Pointer to a read callback. */
+typedef FNVDSCRIPTASREAD *PFNVDSCRIPTASREAD;
+
+/**
+ * Address space write callback
+ *
+ * @returns VBox status code.
+ * @param   pvUser         Opaque user data given on registration.
+ * @param   Address        The address to write to, address is stored in the member for
+ *                         base type given on registration.
+ * @param   pvBuf          Data to write.
+ * @param   cbWrite        How much to write.
+ */
+typedef DECLCALLBACK(int) FNVDSCRIPTASWRITE(void *pvUser, VDSCRIPTARG Address, const void *pvBuf, size_t cbWrite);
+/** Pointer to a write callback. */
+typedef FNVDSCRIPTASWRITE *PFNVDSCRIPTASWRITE;
+
+/**
  * Create a new scripting context.
  *
  * @returns VBox status code.
@@ -150,4 +189,34 @@ DECLHIDDEN(int) VDScriptCtxLoadScript(VDSCRIPTCTX hScriptCtx, const char *pszScr
 DECLHIDDEN(int) VDScriptCtxCallFn(VDSCRIPTCTX hScriptCtx, const char *pszFnCall,
                                   PVDSCRIPTARG paArgs, unsigned cArgs);
 
+/**
+ * Registers a new address space provider.
+ *
+ * @returns VBox status code.
+ * @param   hScriptCtx     The script context handle.
+ * @param   pszType        The type string.
+ * @param   enmBaseType    The base integer type to use for the address space.
+ *                         Bool and String are not supported of course.
+ * @param   pfnRead        The read callback for the registered address space.
+ * @param   pfnWrite       The write callback for the registered address space.
+ * @param   pvUser         Opaque user data to pass to the read and write callbacks.
+ * @param   fFlags         Flags, see VDSCRIPT_AS_FLAGS_*.
+ *
+ * @note This will automatically register a new type with the identifier given in pszType
+ *       used for the pointer. Every variable with this type is automatically treated as a pointer.
+ *
+ * @note If the transitive flag is set the address space stays assigned even if the pointer value
+ *       is casted to another pointer type.
+ *       In the following example the pointer pStruct will use the registered address space for RTGCPHYS
+ *       and dereferencing the pointer causes the read/write callbacks to be triggered.
+ *
+ *       ...
+ *       Struct *pStruct = (Struct *)(RTGCPHYS)0x12345678;
+ *       pStruct->count++;
+ *       ...
+ */
+DECLHIDDEN(int) VDScriptCtxAsRegister(VDSCRIPTCTX hScriptCtx, const char *pszType, VDSCRIPTTYPE enmBaseType,
+                                      PFNVDSCRIPTASREAD pfnRead, PFNVDSCRIPTASWRITE pfnWrite, void *pvUser,
+                                      uint32_t fFlags);
+
 #endif /* _VDScript_h__ */
diff --git a/src/VBox/Storage/testcase/VDScriptAst.cpp b/src/VBox/Storage/testcase/VDScriptAst.cpp
index 8b3d001..b7774c9 100644
--- a/src/VBox/Storage/testcase/VDScriptAst.cpp
+++ b/src/VBox/Storage/testcase/VDScriptAst.cpp
@@ -72,6 +72,13 @@ static void vdScriptAstNodeExpressionPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIP
             }
             break;
         }
+        case VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE:
+        case VDSCRIPTEXPRTYPE_POSTFIX_DOT:
+        {
+            RTListAppend(pList, &pExpr->Deref.pIde->Core.ListNode);
+            RTListAppend(pList, &pExpr->Deref.pExpr->Core.ListNode);
+            break;
+        }
         case VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT:
         case VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT:
         case VDSCRIPTEXPRTYPE_UNARY_INCREMENT:
@@ -80,6 +87,8 @@ static void vdScriptAstNodeExpressionPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIP
         case VDSCRIPTEXPRTYPE_UNARY_NEGSIGN:
         case VDSCRIPTEXPRTYPE_UNARY_INVERT:
         case VDSCRIPTEXPRTYPE_UNARY_NEGATE:
+        case VDSCRIPTEXPRTYPE_UNARY_REFERENCE:
+        case VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE:
         {
             RTListAppend(pList, &pExpr->pExpr->Core.ListNode);
             break;
@@ -153,7 +162,7 @@ static void vdScriptAstNodeStatmentPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIPTA
             /* Put all statements on the to free list. */
             while (!RTListIsEmpty(&pStmt->Compound.ListStmts))
             {
-                PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListDecls, VDSCRIPTASTCORE, ListNode);
+                PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListStmts, VDSCRIPTASTCORE, ListNode);
                 RTListNodeRemove(&pNode->ListNode);
                 RTListAppend(pList, &pNode->ListNode);
             }
@@ -272,7 +281,11 @@ DECLHIDDEN(void) vdScriptAstNodeFree(PVDSCRIPTASTCORE pAstNode)
             case VDSCRIPTASTCLASS_IDENTIFIER:
                 break;
             case VDSCRIPTASTCLASS_DECLARATION:
+            case VDSCRIPTASTCLASS_TYPENAME:
+            {
+                AssertMsgFailed(("TODO\n"));
                 break;
+            }
             case VDSCRIPTASTCLASS_STATEMENT:
             {
                 vdScriptAstNodeStatmentPutOnFreeList(&ListFree, pAstNode);
@@ -314,6 +327,9 @@ DECLHIDDEN(PVDSCRIPTASTCORE) vdScriptAstNodeAlloc(VDSCRIPTASTCLASS enmClass)
         case VDSCRIPTASTCLASS_EXPRESSION:
             cbAlloc = sizeof(VDSCRIPTASTEXPR);
             break;
+        case VDSCRIPTASTCLASS_TYPENAME:
+            cbAlloc = sizeof(VDSCRIPTASTTYPENAME);
+            break;
         case VDSCRIPTASTCLASS_IDENTIFIER:
         case VDSCRIPTASTCLASS_INVALID:
         default:
diff --git a/src/VBox/Storage/testcase/VDScriptAst.h b/src/VBox/Storage/testcase/VDScriptAst.h
index 3f32409..ae6b1ef 100644
--- a/src/VBox/Storage/testcase/VDScriptAst.h
+++ b/src/VBox/Storage/testcase/VDScriptAst.h
@@ -53,6 +53,10 @@ typedef enum VDSCRIPTASTCLASS
     VDSCRIPTASTCLASS_STATEMENT,
     /** Expression node. */
     VDSCRIPTASTCLASS_EXPRESSION,
+    /** Type name node. */
+    VDSCRIPTASTCLASS_TYPENAME,
+    /** Type specifier node. */
+    VDSCRIPTASTCLASS_TYPESPECIFIER,
     /** 32bit blowup. */
     VDSCRIPTASTCLASS_32BIT_HACK = 0x7fffffff
 } VDSCRIPTASTCLASS;
@@ -95,6 +99,105 @@ typedef struct VDSCRIPTASTIDE
 typedef VDSCRIPTASTIDE *PVDSCRIPTASTIDE;
 
 /**
+ * Type specifier.
+ */
+typedef enum VDSCRIPTASTTYPESPECIFIER
+{
+    /** Invalid type specifier. */
+    VDSCRIPTASTTYPESPECIFIER_INVALID = 0,
+    /** Union type specifier. */
+    VDSCRIPTASTTYPESPECIFIER_UNION,
+    /** Struct type specifier. */
+    VDSCRIPTASTTYPESPECIFIER_STRUCT,
+    /** Identifier of a typedefed type. */
+    VDSCRIPTASTTYPESPECIFIER_IDE,
+    /** 32bit hack. */
+    VDSCRIPTASTTYPESPECIFIER_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTTYPESPECIFIER;
+/** Pointer to a typespecifier. */
+typedef VDSCRIPTASTTYPESPECIFIER *PVDSCRIPTASTTYPESPECIFIER;
+
+/**
+ * AST type specifier.
+ */
+typedef struct VDSCRIPTASTTYPESPEC
+{
+    /** Core structure. */
+    VDSCRIPTASTCORE          Core;
+    /** Specifier type. */
+    VDSCRIPTASTTYPESPECIFIER enmType;
+    /** Type dependent data .*/
+    union
+    {
+        /** Pointer to an identifier for typedefed types. */
+        PVDSCRIPTASTIDE      pIde;
+        /** struct or union specifier. */
+        struct
+        {
+            /** Pointer to the identifier, optional. */
+            PVDSCRIPTASTIDE  pIde;
+            /** Declaration list - VDSCRIPTAST. */
+            RTLISTANCHOR     ListDecl;
+        } StructUnion;
+    };
+} VDSCRIPTASTTYPESPEC;
+/** Pointer to an AST type specifier. */
+typedef VDSCRIPTASTTYPESPEC *PVDSCRIPTASTTYPESPEC;
+
+/**
+ * Storage clase specifier.
+ */
+typedef enum VDSCRIPTASTSTORAGECLASS
+{
+    /** Invalid storage class sepcifier. */
+    VDSCRIPTASTSTORAGECLASS_INVALID = 0,
+    /** A typedef type. */
+    VDSCRIPTASTSTORAGECLASS_TYPEDEF,
+    /** An external declared object. */
+    VDSCRIPTASTSTORAGECLASS_EXTERN,
+    /** A static declared object. */
+    VDSCRIPTASTSTORAGECLASS_STATIC,
+    /** Auto object. */
+    VDSCRIPTASTSTORAGECLASS_AUTO,
+    /** Object should be stored in a register. */
+    VDSCRIPTASTSTORAGECLASS_REGISTER,
+    /** 32bit hack. */
+    VDSCRIPTASTSTORAGECLASS_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTSTORAGECLASS;
+/** Pointer to a storage class. */
+typedef VDSCRIPTASTSTORAGECLASS *PVDSCRIPTASTSTORAGECLASS;
+
+/**
+ * Type qualifier.
+ */
+typedef enum VDSCRIPTASTTYPEQUALIFIER
+{
+    /** Invalid type qualifier. */
+    VDSCRIPTASTTYPEQUALIFIER_INVALID = 0,
+    /** Const type qualifier. */
+    VDSCRIPTASTTYPEQUALIFIER_CONST,
+    /** Restrict type qualifier. */
+    VDSCRIPTASTTYPEQUALIFIER_RESTRICT,
+    /** Volatile type qualifier. */
+    VDSCRIPTASTTYPEQUALIFIER_VOLATILE,
+    /** 32bit hack. */
+    VDSCRIPTASTTYPEQUALIFIER_32BIT_HACK = 0x7fffffff
+} VDSCRIPTASTTYPEQUALIFIER;
+/** Pointer to a type qualifier. */
+typedef VDSCRIPTASTTYPEQUALIFIER *PVDSCRIPTASTTYPEQUALIFIER;
+
+/**
+ * AST type name node.
+ */
+typedef struct VDSCRIPTASTTYPENAME
+{
+    /** Core structure. */
+    VDSCRIPTASTCORE    Core;
+} VDSCRIPTASTTYPENAME;
+/** Pointer to a type name node. */
+typedef VDSCRIPTASTTYPENAME *PVDSCRIPTASTTYPENAME;
+
+/**
  * AST declaration node.
  */
 typedef struct VDSCRIPTASTDECL
@@ -129,6 +232,10 @@ typedef enum VDSCRIPTEXPRTYPE
     VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT,
     /** Postfix function call expression. */
     VDSCRIPTEXPRTYPE_POSTFIX_FNCALL,
+    /** Postfix dereference expression. */
+    VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE,
+    /** Dot operator (@todo: Is there a better name for it?). */
+    VDSCRIPTEXPRTYPE_POSTFIX_DOT,
     /** Unary increment expression. */
     VDSCRIPTEXPRTYPE_UNARY_INCREMENT,
     /** Unary decrement expression. */
@@ -141,6 +248,12 @@ typedef enum VDSCRIPTEXPRTYPE
     VDSCRIPTEXPRTYPE_UNARY_INVERT,
     /** Unary negate expression. */
     VDSCRIPTEXPRTYPE_UNARY_NEGATE,
+    /** Unary reference expression. */
+    VDSCRIPTEXPRTYPE_UNARY_REFERENCE,
+    /** Unary dereference expression. */
+    VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE,
+    /** Cast expression. */
+    VDSCRIPTEXPRTYPE_CAST,
     /** Multiplicative expression. */
     VDSCRIPTEXPRTYPE_MULTIPLICATION,
     /** Division expression. */
@@ -245,6 +358,22 @@ typedef struct VDSCRIPTASTEXPR
             /** Right operator. */
             PVDSCRIPTASTEXPR pRightExpr;
         } BinaryOp;
+        /** Dereference or dot operation. */
+        struct
+        {
+            /** The identifier to access. */
+            PVDSCRIPTASTIDE  pIde;
+            /** Postfix expression coming after this. */
+            PVDSCRIPTASTEXPR pExpr;
+        } Deref;
+        /** Cast expression. */
+        struct
+        {
+            /** Type name. */
+            PVDSCRIPTASTTYPENAME pTypeName;
+            /** Following cast expression. */
+            PVDSCRIPTASTEXPR     pExpr;
+        } Cast;
     };
 } VDSCRIPTASTEXPR;
 
diff --git a/src/VBox/Storage/testcase/tstVDCompact.vd b/src/VBox/Storage/testcase/tstVDCompact.vd
index 95532d2..0289978 100644
--- a/src/VBox/Storage/testcase/tstVDCompact.vd
+++ b/src/VBox/Storage/testcase/tstVDCompact.vd
@@ -21,7 +21,7 @@ void tstCompact(string strMsg, string strBackend)
 
     /* Create disk containers, read verification is on. */
     createdisk("disk", true);
-    create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false);
+    create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false, false);
 
     /* Fill the disk with random data. */
     io("disk", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
@@ -45,6 +45,31 @@ void tstCompact(string strMsg, string strBackend)
     destroydisk("disk");
 }
 
+void tstSnapshotCompact(string strMsg, string strBackend)
+{
+    print(strMsg);
+
+    /* Create disk containers, read verification is on. */
+    createdisk("disk", true);
+    create("disk", "base", "tstCompact.disk", "dynamic", strBackend, 200M, false, false);
+
+    /* Fill the disk with random data. */
+    io("disk", false, 1, "seq", 64K, 0, 100M, 100M, 100, "none");
+
+    create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, true /* fHonorSame */);
+
+    io("disk", false, 1, "seq", 64K, 100M, 200M, 100M, 100, "none");
+    io("disk", false, 1, "seq", 64K, 100M, 150M, 50M, 100, "zero");
+
+    create("disk", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, true /* fHonorSame */);
+    merge("disk", 1, 2);
+
+    compact("disk", 1);
+
+    close("disk", "single", true);
+    destroydisk("disk");
+}
+
 void main()
 {
     /* Init I/O RNG for generating random data for writes. */
@@ -56,6 +81,9 @@ void main()
     tstCompact("Testing VDI", "VDI");
     tstCompact("Testing VHD", "VHD");
 
+    tstSnapshotCompact("Testing Snapshot VDI", "VDI");
+    tstSnapshotCompact("Testing Snapshot VHD", "VHD");
+
     /* Destroy RNG and pattern */
     iopatterndestroy("zero");
     iorngdestroy();
diff --git a/src/VBox/Storage/testcase/tstVDCopy.vd b/src/VBox/Storage/testcase/tstVDCopy.vd
index 9cd4e03..d34f27d 100644
--- a/src/VBox/Storage/testcase/tstVDCopy.vd
+++ b/src/VBox/Storage/testcase/tstVDCopy.vd
@@ -23,23 +23,23 @@ void main()
     /* Create source disk and fill data. */
     print("Creating Source Disk");
     createdisk("source", false);
-    create("source", "base", "source_base.vdi", "dynamic", "VDI", 1G, false);
+    create("source", "base", "source_base.vdi", "dynamic", "VDI", 1G, false, false);
     io("source", false, 1, "rnd", 64K, 0, 512M, 256M, 100, "none");
 
     print("Creating first diff");
-    create("source", "diff", "source_diff1.vdi", "dynamic", "VDI", 1G, false);
+    create("source", "diff", "source_diff1.vdi", "dynamic", "VDI", 1G, false, false);
     io("source", false, 1, "rnd", 64K, 512M, 1G, 256M, 50, "none");
 
     print("Creating second diff");
-    create("source", "diff", "source_diff2.vdi", "dynamic", "VDI", 1G, false);
+    create("source", "diff", "source_diff2.vdi", "dynamic", "VDI", 1G, false, false);
     io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
 
     print("Creating third diff");
-    create("source", "diff", "source_diff3.vdi", "dynamic", "VDI", 1G, false);
+    create("source", "diff", "source_diff3.vdi", "dynamic", "VDI", 1G, false, false);
     io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
 
     print("Creating fourth diff");
-    create("source", "diff", "source_diff4.vdi", "dynamic", "VDI", 1G, false);
+    create("source", "diff", "source_diff4.vdi", "dynamic", "VDI", 1G, false, false);
     io("source", false, 1, "rnd", 1M, 0, 1G, 45M, 100, "none");
 
     print("Creating destination disk");
@@ -52,11 +52,11 @@ void main()
     copy("source", "dest", 1, "VDI", "dest_diff1.vdi", false, 0, 0, 0);
 
     print("Copying other diffs optimized");
-    copy("source", "dest", 2, "VDI", "dest_diff1.vdi", false, 0, 1, 1);
-    copy("source", "dest", 3, "VDI", "dest_diff1.vdi", false, 0, 2, 2);
-    copy("source", "dest", 4, "VDI", "dest_diff1.vdi", false, 0, 3, 3);
+    copy("source", "dest", 2, "VDI", "dest_diff2.vdi", false, 0, 1, 1);
+    copy("source", "dest", 3, "VDI", "dest_diff3.vdi", false, 0, 2, 2);
+    copy("source", "dest", 4, "VDI", "dest_diff4.vdi", false, 0, 3, 3);
 
-    print("Comparing_Disks");
+    print("Comparing disks");
     comparedisks("source", "dest");
 
     printfilesize("source", 0);
diff --git a/src/VBox/Storage/testcase/tstVDDiscard.vd b/src/VBox/Storage/testcase/tstVDDiscard.vd
index 56fadf5..3af7c10 100644
--- a/src/VBox/Storage/testcase/tstVDDiscard.vd
+++ b/src/VBox/Storage/testcase/tstVDDiscard.vd
@@ -25,14 +25,14 @@ void main()
     /* Create disk containers, read verification is on. */
     createdisk("disk", true /* fVerify */);
     /* Create the disk. */
-    create("disk", "base", "tstCompact.vdi", "dynamic", "VDI", 2G, false /* fIgnoreFlush */);
+    create("disk", "base", "tstCompact.vdi", "dynamic", "VDI", 2G, false /* fIgnoreFlush */, false);
     /* Fill the disk with random data */
-    io("disk", false, 1, "seq", 64K, 0, 2G, 2G, 100, "none");
+    io("disk", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
     /* Read the data to verify it once. */
-    io("disk", false, 1, "seq", 64K, 0, 2G, 2G,   0, "none");
+    io("disk", false, 1, "seq", 64K, 0, 200M, 200M,   0, "none");
     close("disk", "single", false);
 
-    open("disk", "tstCompact.vdi", "VDI", true, false, false, true, false);
+    open("disk", "tstCompact.vdi", "VDI", true, false, false, true, false, false);
     printfilesize("disk", 0);
     discard("disk", true, "6,0M,512K,1M,512K,2M,512K,3M,512K,4M,512K,5M,512K");
     discard("disk", true, "6,6M,512K,7M,512K,8M,512K,9M,512K,10M,512K,11M,512K");
diff --git a/src/VBox/Storage/testcase/tstVDIo.cpp b/src/VBox/Storage/testcase/tstVDIo.cpp
index 7ab76ea..a8fdad1 100644
--- a/src/VBox/Storage/testcase/tstVDIo.cpp
+++ b/src/VBox/Storage/testcase/tstVDIo.cpp
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (C) 2011-2013 Oracle Corporation
+ * Copyright (C) 2011-2014 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
  * available from http://www.virtualbox.org. This file is free software;
@@ -17,7 +17,6 @@
  */
 #define LOGGROUP LOGGROUP_DEFAULT
 #include <VBox/vd.h>
-#include <VBox/vddbg.h>
 #include <VBox/err.h>
 #include <VBox/log.h>
 #include <iprt/asm.h>
@@ -32,12 +31,22 @@
 #include <iprt/thread.h>
 #include <iprt/rand.h>
 #include <iprt/critsect.h>
+#include <iprt/test.h>
+#include <iprt/system.h>
+
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+# include <VBox/vddbg.h>
+#endif
 
 #include "VDMemDisk.h"
 #include "VDIoBackend.h"
 #include "VDIoRnd.h"
 
 #include "VDScript.h"
+#include "BuiltinTests.h"
+
+/** forward declaration for the global test data pointer. */
+typedef struct VDTESTGLOB *PVDTESTGLOB;
 
 /**
  * A virtual file backed by memory.
@@ -98,6 +107,8 @@ typedef struct VDDISK
     VDGEOMETRY     PhysGeom;
     /** Logical CHS geometry. */
     VDGEOMETRY     LogicalGeom;
+    /** Global test data. */
+    PVDTESTGLOB    pTestGlob;
 } VDDISK, *PVDDISK;
 
 /**
@@ -140,7 +151,9 @@ typedef struct VDTESTGLOB
     PVDIORND         pIoRnd;
     /** Current storage backend to use. */
     char            *pszIoBackend;
-} VDTESTGLOB, *PVDTESTGLOB;
+    /** Testcase handle. */
+    RTTEST           hTest;
+} VDTESTGLOB;
 
 /**
  * Transfer direction.
@@ -227,7 +240,6 @@ static DECLCALLBACK(int) vdScriptHandlerDiscard(PVDSCRIPTARG paScriptArgs, void
 static DECLCALLBACK(int) vdScriptHandlerCopy(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerClose(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerPrintFileSize(PVDSCRIPTARG paScriptArgs, void *pvUser);
-static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerIoRngDestroy(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromNumber(PVDSCRIPTARG paScriptArgs, void *pvUser);
@@ -245,6 +257,10 @@ static DECLCALLBACK(int) vdScriptHandlerResetStatistics(PVDSCRIPTARG paScriptArg
 static DECLCALLBACK(int) vdScriptHandlerResize(PVDSCRIPTARG paScriptArgs, void *pvUser);
 static DECLCALLBACK(int) vdScriptHandlerSetFileBackend(PVDSCRIPTARG paScriptArgs, void *pvUser);
 
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
+static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser);
+#endif
+
 /* create action */
 const VDSCRIPTTYPE g_aArgCreate[] =
 {
@@ -254,6 +270,7 @@ const VDSCRIPTTYPE g_aArgCreate[] =
     VDSCRIPTTYPE_STRING,
     VDSCRIPTTYPE_STRING,
     VDSCRIPTTYPE_UINT64,
+    VDSCRIPTTYPE_BOOL,
     VDSCRIPTTYPE_BOOL
 };
 
@@ -267,7 +284,8 @@ const VDSCRIPTTYPE g_aArgOpen[] =
     VDSCRIPTTYPE_BOOL,   /* shareable */
     VDSCRIPTTYPE_BOOL,   /* readonly */
     VDSCRIPTTYPE_BOOL,   /* discard */
-    VDSCRIPTTYPE_BOOL    /* ignoreflush */
+    VDSCRIPTTYPE_BOOL,   /* ignoreflush */
+    VDSCRIPTTYPE_BOOL,   /* honorsame */
 };
 
 /* I/O action */
@@ -344,12 +362,14 @@ const VDSCRIPTTYPE g_aArgPrintFileSize[] =
     VDSCRIPTTYPE_UINT32 /* image */
 };
 
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
 /* print file size action */
 const VDSCRIPTTYPE g_aArgIoLogReplay[] =
 {
     VDSCRIPTTYPE_STRING, /* disk */
     VDSCRIPTTYPE_STRING  /* iolog */
 };
+#endif
 
 /* I/O RNG create action */
 const VDSCRIPTTYPE g_aArgIoRngCreate[] =
@@ -459,7 +479,9 @@ const VDSCRIPTCALLBACK g_aScriptActions[] =
     {"flush",                      VDSCRIPTTYPE_VOID, g_aArgFlush,                       RT_ELEMENTS(g_aArgFlush),                      vdScriptHandlerFlush},
     {"close",                      VDSCRIPTTYPE_VOID, g_aArgClose,                       RT_ELEMENTS(g_aArgClose),                      vdScriptHandlerClose},
     {"printfilesize",              VDSCRIPTTYPE_VOID, g_aArgPrintFileSize,               RT_ELEMENTS(g_aArgPrintFileSize),              vdScriptHandlerPrintFileSize},
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
     {"ioreplay",                   VDSCRIPTTYPE_VOID, g_aArgIoLogReplay,                 RT_ELEMENTS(g_aArgIoLogReplay),                vdScriptHandlerIoLogReplay},
+#endif
     {"merge",                      VDSCRIPTTYPE_VOID, g_aArgMerge,                       RT_ELEMENTS(g_aArgMerge),                      vdScriptHandlerMerge},
     {"compact",                    VDSCRIPTTYPE_VOID, g_aArgCompact,                     RT_ELEMENTS(g_aArgCompact),                    vdScriptHandlerCompact},
     {"discard",                    VDSCRIPTTYPE_VOID, g_aArgDiscard,                     RT_ELEMENTS(g_aArgDiscard),                    vdScriptHandlerDiscard},
@@ -531,6 +553,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
     bool fBase = false;
     bool fDynamic = true;
     bool fIgnoreFlush = false;
+    bool fHonorSame = false;
     PVDIOBACKEND pIoBackend = NULL;
 
     pcszDisk = paScriptArgs[0].psz;
@@ -556,6 +579,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
     pcszBackend = paScriptArgs[4].psz;
     cbSize = paScriptArgs[5].u64;
     fIgnoreFlush = paScriptArgs[6].f;
+    fHonorSame = paScriptArgs[7].f;
 
     if (RT_SUCCESS(rc))
     {
@@ -571,6 +595,9 @@ static DECLCALLBACK(int) vdScriptHandlerCreate(PVDSCRIPTARG paScriptArgs, void *
             if (fIgnoreFlush)
                 fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
 
+            if (fHonorSame)
+                fOpenFlags |= VD_OPEN_FLAGS_HONOR_SAME;
+
             if (fBase)
                 rc = VDCreateBase(pDisk->pVD, pcszBackend, pcszImage, cbSize, fImageFlags, NULL,
                                   &pDisk->PhysGeom, &pDisk->LogicalGeom,
@@ -599,6 +626,7 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
     bool fAsyncIo  = true;
     bool fDiscard  = false;
     bool fIgnoreFlush = false;
+    bool fHonorSame = false;
 
     pcszDisk = paScriptArgs[0].psz;
     pcszImage = paScriptArgs[1].psz;
@@ -607,6 +635,8 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
     fReadonly = paScriptArgs[4].f;
     fAsyncIo = paScriptArgs[5].f;
     fDiscard = paScriptArgs[6].f;
+    fIgnoreFlush = paScriptArgs[7].f;
+    fHonorSame = paScriptArgs[8].f;
 
     if (RT_SUCCESS(rc))
     {
@@ -625,6 +655,8 @@ static DECLCALLBACK(int) vdScriptHandlerOpen(PVDSCRIPTARG paScriptArgs, void *pv
                 fOpenFlags |= VD_OPEN_FLAGS_DISCARD;
             if (fIgnoreFlush)
                 fOpenFlags |= VD_OPEN_FLAGS_IGNORE_FLUSH;
+            if (fHonorSame)
+                fOpenFlags |= VD_OPEN_FLAGS_HONOR_SAME;
 
             rc = VDOpen(pDisk->pVD, pcszBackend, pcszImage, fOpenFlags, pGlob->pInterfacesImages);
         }
@@ -711,6 +743,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
     {
         VDIOTEST IoTest;
 
+        RTTestSub(pGlob->hTest, "Basic I/O");
         rc = tstVDIoTestInit(&IoTest, pGlob, fRandomAcc, cbIo, cbBlkSize, offStart, offEnd, uWriteChance, pPattern);
         if (RT_SUCCESS(rc))
         {
@@ -769,7 +802,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
 
                                                 if (VDMemDiskCmp(pDisk->pMemDiskVerify, paIoReq[idx].off, paIoReq[idx].cbReq, &SgBuf))
                                                 {
-                                                    RTPrintf("Corrupted disk at offset %llu!\n", paIoReq[idx].off);
+                                                    RTTestFailed(pGlob->hTest, "Corrupted disk at offset %llu!\n", paIoReq[idx].off);
                                                     rc = VERR_INVALID_STATE;
                                                 }
                                             }
@@ -848,7 +881,7 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
                                                     if (VDMemDiskCmp(pDisk->pMemDiskVerify, paIoReq[idx].off, paIoReq[idx].cbReq,
                                                                      &paIoReq[idx].SgBuf))
                                                     {
-                                                        RTPrintf("Corrupted disk at offset %llu!\n", paIoReq[idx].off);
+                                                        RTTestFailed(pGlob->hTest, "Corrupted disk at offset %llu!\n", paIoReq[idx].off);
                                                         rc = VERR_INVALID_STATE;
                                                     }
                                                     RTCritSectLeave(&pDisk->CritSectVerify);
@@ -922,7 +955,13 @@ static DECLCALLBACK(int) vdScriptHandlerIo(PVDSCRIPTARG paScriptArgs, void *pvUs
 
                 NanoTS = RTTimeNanoTS() - NanoTS;
                 uint64_t SpeedKBs = (uint64_t)(cbIo / (NanoTS / 1000000000.0) / 1024);
-                RTPrintf("I/O Test: Throughput %lld kb/s\n", SpeedKBs);
+                RTTestValue(pGlob->hTest, "Throughput", SpeedKBs, RTTESTUNIT_KILOBYTES_PER_SEC);
+
+                for (unsigned i = 0; i < cMaxTasksOutstanding; i++)
+                {
+                    if (paIoReq[i].pvBufRead)
+                        RTMemFree(paIoReq[i].pvBufRead);
+                }
 
                 RTSemEventDestroy(EventSem);
                 RTMemFree(paIoReq);
@@ -1363,6 +1402,7 @@ static DECLCALLBACK(int) vdScriptHandlerPrintFileSize(PVDSCRIPTARG paScriptArgs,
 }
 
 
+#ifdef VBOX_TSTVDIO_WITH_LOG_REPLAY
 static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, void *pvUser)
 {
     int rc = VINF_SUCCESS;
@@ -1513,6 +1553,7 @@ static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDSCRIPTARG paScriptArgs, v
 
     return rc;
 }
+#endif
 
 
 static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDSCRIPTARG paScriptArgs, void *pvUser)
@@ -1744,6 +1785,7 @@ static DECLCALLBACK(int) vdScriptHandlerCreateDisk(PVDSCRIPTARG paScriptArgs, vo
         pDisk = (PVDDISK)RTMemAllocZ(sizeof(VDDISK));
         if (pDisk)
         {
+            pDisk->pTestGlob = pGlob;
             pDisk->pszName = RTStrDup(pcszDisk);
             if (pDisk->pszName)
             {
@@ -1844,8 +1886,9 @@ static DECLCALLBACK(int) vdScriptHandlerCompareDisks(PVDSCRIPTARG paScriptArgs,
             cbDisk1 = VDGetSize(pDisk1->pVD, VD_LAST_IMAGE);
             cbDisk2 = VDGetSize(pDisk2->pVD, VD_LAST_IMAGE);
 
+            RTTestSub(pGlob->hTest, "Comparing two disks for equal content");
             if (cbDisk1 != cbDisk2)
-                RTPrintf("Disks differ in size %llu vs %llu\n", cbDisk1, cbDisk2);
+                RTTestFailed(pGlob->hTest, "Disks differ in size %llu vs %llu\n", cbDisk1, cbDisk2);
             else
             {
                 while (uOffCur < cbDisk1)
@@ -1860,14 +1903,14 @@ static DECLCALLBACK(int) vdScriptHandlerCompareDisks(PVDSCRIPTARG paScriptArgs,
                     {
                         if (memcmp(pbBuf1, pbBuf2, cbRead))
                         {
-                            RTPrintf("Disks differ at offset %llu\n", uOffCur);
+                            RTTestFailed(pGlob->hTest, "Disks differ at offset %llu\n", uOffCur);
                             rc = VERR_DEV_IO_ERROR;
                             break;
                         }
                     }
                     else
                     {
-                        RTPrintf("Reading one disk at offset %llu failed\n", uOffCur);
+                        RTTestFailed(pGlob->hTest, "Reading one disk at offset %llu failed\n", uOffCur);
                         break;
                     }
 
@@ -1990,7 +2033,7 @@ static DECLCALLBACK(int) vdScriptHandlerResize(PVDSCRIPTARG paScriptArgs, void *
     int rc = VINF_SUCCESS;
     PVDTESTGLOB pGlob = (PVDTESTGLOB)pvUser;
     const char *pcszDisk = paScriptArgs[0].psz;
-    uint64_t cbDiskNew = 0;
+    uint64_t cbDiskNew = paScriptArgs[1].u64;
     PVDDISK pDisk = NULL;
 
     pDisk = tstVDIoGetDiskByName(pGlob, pcszDisk);
@@ -2515,7 +2558,7 @@ static void tstVDIoTestReqComplete(void *pvUser1, void *pvUser2, int rcReq)
 
                 if (VDMemDiskCmp(pDisk->pMemDiskVerify, pIoReq->off, pIoReq->cbReq,
                                  &pIoReq->SgBuf))
-                    RTPrintf("Corrupted disk at offset %llu!\n", pIoReq->off);
+                    RTTestFailed(pDisk->pTestGlob->hTest, "Corrupted disk at offset %llu!\n", pIoReq->off);
                 RTCritSectLeave(&pDisk->CritSectVerify);
             }
             case VDIOREQTXDIR_WRITE:
@@ -2647,18 +2690,15 @@ static int tstVDIoPatternGetBuffer(PVDPATTERN pPattern, void **ppv, size_t cb)
 }
 
 /**
- * Executes the given I/O script using the new scripting engine.
+ * Executes the given script.
  *
  * @returns nothing.
- *
- * @param pcszFilename    The script to execute.
+ * @param   pszScript    The script to execute.
  */
-static void tstVDIoScriptRun(const char *pcszFilename)
+static void tstVDIoScriptExec(const char *pszScript)
 {
     int rc = VINF_SUCCESS;
     VDTESTGLOB GlobTest;   /**< Global test data. */
-    void *pvFile = NULL;
-    size_t cbFile = 0;
 
     memset(&GlobTest, 0, sizeof(VDTESTGLOB));
     RTListInit(&GlobTest.ListFiles);
@@ -2671,40 +2711,36 @@ static void tstVDIoScriptRun(const char *pcszFilename)
         return;
     }
 
-    rc = RTFileReadAll(pcszFilename, &pvFile, &cbFile);
+    /* Init global test data. */
+    GlobTest.VDIfError.pfnError     = tstVDError;
+    GlobTest.VDIfError.pfnMessage   = tstVDMessage;
+
+    rc = VDInterfaceAdd(&GlobTest.VDIfError.Core, "tstVDIo_VDIError", VDINTERFACETYPE_ERROR,
+                        NULL, sizeof(VDINTERFACEERROR), &GlobTest.pInterfacesDisk);
+    AssertRC(rc);
+
+    GlobTest.VDIfIo.pfnOpen                = tstVDIoFileOpen;
+    GlobTest.VDIfIo.pfnClose               = tstVDIoFileClose;
+    GlobTest.VDIfIo.pfnDelete              = tstVDIoFileDelete;
+    GlobTest.VDIfIo.pfnMove                = tstVDIoFileMove;
+    GlobTest.VDIfIo.pfnGetFreeSpace        = tstVDIoFileGetFreeSpace;
+    GlobTest.VDIfIo.pfnGetModificationTime = tstVDIoFileGetModificationTime;
+    GlobTest.VDIfIo.pfnGetSize             = tstVDIoFileGetSize;
+    GlobTest.VDIfIo.pfnSetSize             = tstVDIoFileSetSize;
+    GlobTest.VDIfIo.pfnWriteSync           = tstVDIoFileWriteSync;
+    GlobTest.VDIfIo.pfnReadSync            = tstVDIoFileReadSync;
+    GlobTest.VDIfIo.pfnFlushSync           = tstVDIoFileFlushSync;
+    GlobTest.VDIfIo.pfnReadAsync           = tstVDIoFileReadAsync;
+    GlobTest.VDIfIo.pfnWriteAsync          = tstVDIoFileWriteAsync;
+    GlobTest.VDIfIo.pfnFlushAsync          = tstVDIoFileFlushAsync;
+
+    rc = VDInterfaceAdd(&GlobTest.VDIfIo.Core, "tstVDIo_VDIIo", VDINTERFACETYPE_IO,
+                        &GlobTest, sizeof(VDINTERFACEIO), &GlobTest.pInterfacesImages);
+    AssertRC(rc);
+
+    rc = RTTestCreate("tstVDIo", &GlobTest.hTest);
     if (RT_SUCCESS(rc))
     {
-        char *pszScript = RTStrDupN((char *)pvFile, cbFile);
-        RTFileReadAllFree(pvFile, cbFile);
-
-        AssertPtr(pszScript);
-        /* Init global test data. */
-        GlobTest.VDIfError.pfnError     = tstVDError;
-        GlobTest.VDIfError.pfnMessage   = tstVDMessage;
-
-        rc = VDInterfaceAdd(&GlobTest.VDIfError.Core, "tstVDIo_VDIError", VDINTERFACETYPE_ERROR,
-                            NULL, sizeof(VDINTERFACEERROR), &GlobTest.pInterfacesDisk);
-        AssertRC(rc);
-
-        GlobTest.VDIfIo.pfnOpen                = tstVDIoFileOpen;
-        GlobTest.VDIfIo.pfnClose               = tstVDIoFileClose;
-        GlobTest.VDIfIo.pfnDelete              = tstVDIoFileDelete;
-        GlobTest.VDIfIo.pfnMove                = tstVDIoFileMove;
-        GlobTest.VDIfIo.pfnGetFreeSpace        = tstVDIoFileGetFreeSpace;
-        GlobTest.VDIfIo.pfnGetModificationTime = tstVDIoFileGetModificationTime;
-        GlobTest.VDIfIo.pfnGetSize             = tstVDIoFileGetSize;
-        GlobTest.VDIfIo.pfnSetSize             = tstVDIoFileSetSize;
-        GlobTest.VDIfIo.pfnWriteSync           = tstVDIoFileWriteSync;
-        GlobTest.VDIfIo.pfnReadSync            = tstVDIoFileReadSync;
-        GlobTest.VDIfIo.pfnFlushSync           = tstVDIoFileFlushSync;
-        GlobTest.VDIfIo.pfnReadAsync           = tstVDIoFileReadAsync;
-        GlobTest.VDIfIo.pfnWriteAsync          = tstVDIoFileWriteAsync;
-        GlobTest.VDIfIo.pfnFlushAsync          = tstVDIoFileFlushAsync;
-
-        rc = VDInterfaceAdd(&GlobTest.VDIfIo.Core, "tstVDIo_VDIIo", VDINTERFACETYPE_IO,
-                            &GlobTest, sizeof(VDINTERFACEIO), &GlobTest.pInterfacesImages);
-        AssertRC(rc);
-
         /* Init I/O backend. */
         rc = VDIoBackendCreate(&GlobTest.pIoBackend);
         if (RT_SUCCESS(rc))
@@ -2713,9 +2749,10 @@ static void tstVDIoScriptRun(const char *pcszFilename)
             rc = VDScriptCtxCreate(&hScriptCtx);
             if (RT_SUCCESS(rc))
             {
-                rc = VDScriptCtxCallbacksRegister(hScriptCtx, g_aScriptActions, g_cScriptActions, &GlobTest);
-                AssertRC(rc);
+                RTTEST_CHECK_RC_OK(GlobTest.hTest,
+                                   VDScriptCtxCallbacksRegister(hScriptCtx, g_aScriptActions, g_cScriptActions, &GlobTest));
 
+                RTTestBanner(GlobTest.hTest);
                 rc = VDScriptCtxLoadScript(hScriptCtx, pszScript);
                 if (RT_FAILURE(rc))
                 {
@@ -2729,14 +2766,80 @@ static void tstVDIoScriptRun(const char *pcszFilename)
         }
         else
             RTPrintf("Creating the I/O backend failed rc=%Rrc\n");
+
+        RTTestSummaryAndDestroy(GlobTest.hTest);
     }
     else
-        RTPrintf("Opening script failed rc=%Rrc\n", rc);
+        RTStrmPrintf(g_pStdErr, "tstVDIo: fatal error: RTTestCreate failed with rc=%Rrc\n", rc);
 
     RTStrFree(GlobTest.pszIoBackend);
 }
 
 /**
+ * Executes the given I/O script using the new scripting engine.
+ *
+ * @returns nothing.
+ *
+ * @param pcszFilename    The script to execute.
+ */
+static void tstVDIoScriptRun(const char *pcszFilename)
+{
+    int rc = VINF_SUCCESS;
+    void *pvFile = NULL;
+    size_t cbFile = 0;
+
+    rc = RTFileReadAll(pcszFilename, &pvFile, &cbFile);
+    if (RT_SUCCESS(rc))
+    {
+        char *pszScript = RTStrDupN((char *)pvFile, cbFile);
+        RTFileReadAllFree(pvFile, cbFile);
+
+        AssertPtr(pszScript);
+        tstVDIoScriptExec(pszScript);
+        RTStrFree(pszScript);
+    }
+    else
+        RTPrintf("Opening the script failed: %Rrc\n", rc);
+
+}
+
+/**
+ * Run builtin tests.
+ *
+ * @returns nothing.
+ */
+static void tstVDIoRunBuiltinTests(void)
+{
+    /* 32bit hosts are excluded because of the 4GB address space. */
+#if HC_ARCH_BITS == 32
+    RTStrmPrintf(g_pStdErr, "tstVDIo: Running on a 32bit host is not supported for the builtin tests, skipping\n");
+    return;
+#else
+    /*
+     * We need quite a bit of RAM for the builtin tests. Skip it if there
+     * is not enough free RAM available.
+     */
+    uint64_t cbFree = 0;
+    int rc = RTSystemQueryAvailableRam(&cbFree);
+    if (   RT_FAILURE(rc)
+        || cbFree < (UINT64_C(6) * _1G))
+    {
+        RTStrmPrintf(g_pStdErr, "tstVDIo: fatal error: Failed to query available RAM or not enough available, skipping (rc=%Rrc cbFree=%llu)\n",
+                     rc, cbFree);
+        return;
+    }
+
+    for (unsigned i = 0; i < g_cVDIoTests; i++)
+    {
+        char *pszScript = RTStrDupN((const char *)g_aVDIoTests[i].pch, g_aVDIoTests[i].cb);
+
+        AssertPtr(pszScript);
+        tstVDIoScriptExec(pszScript);
+    }
+#endif
+}
+
+/**
  * Shows help message.
  */
 static void printUsage(void)
@@ -2747,28 +2850,28 @@ static void printUsage(void)
 
 static const RTGETOPTDEF g_aOptions[] =
 {
-    { "--script",   's', RTGETOPT_REQ_STRING }
+    { "--script",   's', RTGETOPT_REQ_STRING },
+    { "--help",     'h', RTGETOPT_REQ_NOTHING }
 };
 
 int main(int argc, char *argv[])
 {
-#if 0 /** @todo: Enable when the testcase was fixed. */
     RTR3InitExe(argc, &argv, 0);
     int rc;
     RTGETOPTUNION ValueUnion;
     RTGETOPTSTATE GetState;
     char c;
 
-    if (argc != 3)
-    {
-        printUsage();
-        return RTEXITCODE_FAILURE;
-    }
-
     rc = VDInit();
     if (RT_FAILURE(rc))
         return RTEXITCODE_FAILURE;
 
+    if (argc == 1)
+    {
+        tstVDIoRunBuiltinTests();
+        return RTEXITCODE_SUCCESS;
+    }
+
     RTGetOptInit(&GetState, argc, argv, g_aOptions,
                  RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
 
@@ -2780,15 +2883,17 @@ int main(int argc, char *argv[])
             case 's':
                 tstVDIoScriptRun(ValueUnion.psz);
                 break;
-            default:
+            case 'h':
                 printUsage();
+                break;
+            default: /* Default is to run built in tests if no arguments are given (automated testing). */
+                tstVDIoRunBuiltinTests();
         }
     }
 
     rc = VDShutdown();
     if (RT_FAILURE(rc))
         RTPrintf("tstVDIo: unloading backends failed! rc=%Rrc\n", rc);
-#endif
 
     return RTEXITCODE_SUCCESS;
 }
diff --git a/src/VBox/Storage/testcase/tstVDIo.vd b/src/VBox/Storage/testcase/tstVDIo.vd
index 0074be6..3eae4f6 100644
--- a/src/VBox/Storage/testcase/tstVDIo.vd
+++ b/src/VBox/Storage/testcase/tstVDIo.vd
@@ -19,15 +19,15 @@ void tstIo(string strMessage, string strBackend)
 {
     print(strMessage);
     createdisk("test", true /* fVerify */);
-    create("test", "base", "tst.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+    create("test", "base", "tst.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
     io("test", true, 32, "seq", 64K, 0, 200M, 200M, 100, "none");
     io("test", false, 1, "seq", 64K, 0, 200M, 200M, 100, "none");
     io("test", true, 32, "seq", 64K, 0, 200M, 200M,   0, "none");
     io("test", false, 1, "seq", 64K, 0, 200M, 200M,   0, "none");
-    create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+    create("test", "diff", "tst2.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
     io("test", true, 32, "rnd", 64K, 0, 200M, 200M,  50, "none");
     io("test", false, 1, "rnd", 64K, 0, 200M, 200M,  50, "none");
-    create("test", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */);
+    create("test", "diff", "tst3.disk", "dynamic", strBackend, 200M, false /* fIgnoreFlush */, false);
     io("test", true, 32, "rnd", 64K, 0, 200M, 200M,  50, "none");
     io("test", false, 1, "rnd", 64K, 0, 200M, 200M,  50, "none");
     close("test", "single", true /* fDelete */);
@@ -36,6 +36,16 @@ void tstIo(string strMessage, string strBackend)
     destroydisk("test");
 }
 
+void tstIoUnaligned(string strMessage, string strBackend)
+{
+    print(strMessage);
+    createdisk("test", true);
+    create("test", "base", "tst.disk", "dynamic", strBackend, 2G, false);
+    io("test", false, 1, "seq", 512, 3584, 4096, 512, 100, "none");
+    io("test", false, 1, "seq", 512, 3584, 4096, 512,   0, "none");
+    destroydisk("test");
+}
+
 void main()
 {
     /* Init I/O RNG for generating random data for writes */
diff --git a/src/VBox/Storage/testcase/tstVDMultBackends.vd b/src/VBox/Storage/testcase/tstVDMultBackends.vd
new file mode 100644
index 0000000..fa3f9c3
--- /dev/null
+++ b/src/VBox/Storage/testcase/tstVDMultBackends.vd
@@ -0,0 +1,60 @@
+/* $Id: tstVDMultBackends.vd $ */
+/**
+ * Storage: Simple I/O test with different backends in one chain.
+ */
+
+/*
+ * Copyright (C) 2011-2013 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.
+ */
+
+void tstIo(string strMessage, string strBackend)
+{
+    print(strMessage);
+    createdisk("test", true /* fVerify */);
+    create("test", "base", "tst.disk", "dynamic", strBackend, 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "seq", 64K, 0, 2G, 200M, 100, "none");
+    io("test", false, 1, "seq", 64K, 0, 2G, 200M, 100, "none");
+    io("test", true, 32, "seq", 64K, 0, 2G, 200M,   0, "none");
+    io("test", false, 1, "seq", 64K, 0, 2G, 200M,   0, "none");
+    create("test", "diff", "tst2.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    io("test", false, 1, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    create("test", "diff", "tst3.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    io("test", false, 1, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    create("test", "diff", "tst4.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,   0, "none");
+
+    create("test", "diff", "tst5.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,   0, "none");
+
+    create("test", "diff", "tst6.disk", "dynamic", "VMDK", 2G, false /* fIgnoreFlush */, false);
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,  50, "none");
+    io("test", true, 32, "rnd", 64K, 0, 2G, 200M,   0, "none");
+
+    close("test", "single", true /* fDelete */);
+    close("test", "single", true /* fDelete */);
+    close("test", "single", true /* fDelete */);
+    destroydisk("test");
+}
+
+void main()
+{
+    /* Init I/O RNG for generating random data for writes */
+    iorngcreate(10M, "manual", 1234567890);
+
+    tstIo("Testing VDI", "VDI");
+
+    iorngdestroy();
+}
+
diff --git a/src/VBox/Storage/testcase/tstVDResize.vd b/src/VBox/Storage/testcase/tstVDResize.vd
index 0a3dcf4..8e74d35 100644
--- a/src/VBox/Storage/testcase/tstVDResize.vd
+++ b/src/VBox/Storage/testcase/tstVDResize.vd
@@ -17,16 +17,17 @@
 
 void main()
 {
-	/* Init I/O RNG for generating random data for writes. */
-	iorngcreate(10M, "manual", 1234567890);
+    /* Init I/O RNG for generating random data for writes. */
+    iorngcreate(10M, "manual", 1234567890);
 
-	print("Testing VDI");
-	createdisk("test", true);
-	create("test", "base", "tst.vdi", "dynamic", "VDI", 1T, false);
-	io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 100, "none");
-	resize("test", 1331200M);
-	io("test", false, 1, "seq", 64K, 255G, 257G, 2G,   0, "none");
-	destroydisk("test");
+    print("Testing VDI");
+    createdisk("test", true);
+    create("test", "base", "tst.vdi", "dynamic", "VDI", 1T, false, false);
+    io("test", false, 1, "seq", 64K, 255G, 257G, 2G, 100, "none");
+    resize("test", 1331200M);
+    io("test", false, 1, "seq", 64K, 255G, 257G, 2G,   0, "none");
+    destroydisk("test");
 
-	iorngdestroy();
+    iorngdestroy();
 }
+
diff --git a/src/VBox/Storage/testcase/tstVDShareable.vd b/src/VBox/Storage/testcase/tstVDShareable.vd
index 7cbe4e2..6fdf032 100644
--- a/src/VBox/Storage/testcase/tstVDShareable.vd
+++ b/src/VBox/Storage/testcase/tstVDShareable.vd
@@ -25,12 +25,12 @@ void main()
     createdisk("shared2", false);
 
     /* Create the disk and close it. */
-    create("shared1", "base", "tstShared.vdi", "fixed", "VDI", 20M, false);
+    create("shared1", "base", "tstShared.vdi", "fixed", "VDI", 20M, false, false);
     close("shared1", "all", false);
 
     /* Open the disk with sharing enabled. */
-    open("shared1", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false);
-    open("shared2", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false);
+    open("shared1", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false, false);
+    open("shared2", "tstShared.vdi", "VDI", true /* fAsync */, true /* fShareable */, false, false, false, false);
 
     /* Write to one disk and verify that the other disk can see the content. */
     io("shared1", true, 32, "seq", 64K, 0, 20M, 20M, 100, "none");
@@ -45,7 +45,7 @@ void main()
     close("shared2", "all", false);
 
     /* Open and delete. */
-    open("shared1", "tstShared.vdi", "VDI", false /* fAsync */, false /* fShareable */, false, false, false);
+    open("shared1", "tstShared.vdi", "VDI", false /* fAsync */, false /* fShareable */, false, false, false, false);
     close("shared1", "single", true);
 
     /* Cleanup */
@@ -53,3 +53,4 @@ void main()
     destroydisk("shared2");
     iorngdestroy();
 }
+
diff --git a/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp b/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
index 32cc236..88d2358 100644
--- a/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
+++ b/src/VBox/VMM/VMMAll/IOMAllMMIO.cpp
@@ -93,7 +93,7 @@ static const unsigned g_aSize2Shift[] =
 static VBOXSTRICTRC iomMMIODoComplicatedWrite(PVM pVM, PIOMMMIORANGE pRange, RTGCPHYS GCPhys, void const *pvValue, unsigned cbValue)
 {
     AssertReturn(   (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) != IOMMMIO_FLAGS_WRITE_PASSTHRU
-                 || (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
+                 && (pRange->fFlags & IOMMMIO_FLAGS_WRITE_MODE) <= IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING,
                  VERR_IOM_MMIO_IPE_1);
     AssertReturn(cbValue != 0 && cbValue <= 16, VERR_IOM_MMIO_IPE_2);
     RTGCPHYS const GCPhysStart  = GCPhys; NOREF(GCPhysStart);
diff --git a/src/VBox/VMM/VMMR0/HMSVMR0.cpp b/src/VBox/VMM/VMMR0/HMSVMR0.cpp
index 8738755..26d876f 100644
--- a/src/VBox/VMM/VMMR0/HMSVMR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMSVMR0.cpp
@@ -4923,9 +4923,20 @@ HMSVM_EXIT_DECL hmR0SvmExitXcptMF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSv
 
     if (!(pCtx->cr0 & X86_CR0_NE))
     {
-        /* Old-style FPU error reporting needs some extra work. */
-        /** @todo don't fall back to the recompiler, but do it manually. */
-        return VERR_EM_INTERPRETER;
+        PVM         pVM  = pVCpu->CTX_SUFF(pVM);
+        PDISSTATE   pDis = &pVCpu->hm.s.DisState;
+        unsigned    cbOp;
+        int rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
+        if (RT_SUCCESS(rc))
+        {
+            /* Convert a #MF into a FERR -> IRQ 13. */
+            rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /*uTagSrc*/);
+            if (RT_SUCCESS(rc))
+                pCtx->rip += cbOp;
+        }
+        else
+            Log4(("hmR0SvmExitXcptMF: EMInterpretDisasCurrent returned %Rrc uOpCode=%#x\n", rc, pDis->pCurInstr->uOpcode));
+        return rc;
     }
 
     hmR0SvmSetPendingXcptMF(pVCpu);
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index 92ff4db..cced81e 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -8724,17 +8724,17 @@ static uint32_t hmR0VmxCheckGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
             HMVMX_CHECK_BREAK(!(u64Val & UINT64_C(0x707070707070707)), VMX_IGS_PAT_MSR_RESERVED);
             for (unsigned i = 0; i < 8; i++)
             {
-                uint8_t u8Val = (u64Val & 0x7);
+                uint8_t u8Val = (u64Val & 0xff);
                 if (   u8Val != 0 /* UC */
-                    || u8Val != 1 /* WC */
-                    || u8Val != 4 /* WT */
-                    || u8Val != 5 /* WP */
-                    || u8Val != 6 /* WB */
-                    || u8Val != 7 /* UC- */)
+                    && u8Val != 1 /* WC */
+                    && u8Val != 4 /* WT */
+                    && u8Val != 5 /* WP */
+                    && u8Val != 6 /* WB */
+                    && u8Val != 7 /* UC- */)
                 {
                     HMVMX_ERROR_BREAK(VMX_IGS_PAT_MSR_INVALID);
                 }
-                u64Val >>= 3;
+                u64Val >>= 8;
             }
         }
 
@@ -10749,9 +10749,11 @@ static int hmR0VmxExitXcptMF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVm
 
     if (!(pMixedCtx->cr0 & X86_CR0_NE))
     {
-        /* Old-style FPU error reporting needs some extra work. */
-        /** @todo don't fall back to the recompiler, but do it manually. */
-        return VERR_EM_INTERPRETER;
+        /* Convert a #MF into a FERR -> IRQ 13. */
+        rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /*uTagSrc*/);
+        int rc2 = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
+        AssertRCReturn(rc2, rc2);
+        return rc;
     }
 
     hmR0VmxSetPendingEvent(pVCpu, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(pVmxTransient->uExitIntInfo),
diff --git a/src/VBox/VMM/VMMR3/MMPagePool.cpp b/src/VBox/VMM/VMMR3/MMPagePool.cpp
index e40bb3d..6716e75 100644
--- a/src/VBox/VMM/VMMR3/MMPagePool.cpp
+++ b/src/VBox/VMM/VMMR3/MMPagePool.cpp
@@ -231,7 +231,7 @@ DECLINLINE(void *) mmR3PagePoolAlloc(PMMPAGEPOOL pPool)
     unsigned        cPages = !pPool->fLow ? 128 : 32;
     PMMPAGESUBPOOL  pSub;
     int rc = MMHyperAlloc(pPool->pVM,
-                          RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0] * 8))])
+                          RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)])
                           + (sizeof(SUPPAGE) + sizeof(MMPPLOOKUPHCPHYS)) * cPages
                           + sizeof(MMPPLOOKUPHCPTR),
                           0,
diff --git a/src/VBox/VMM/VMMR3/PGMPhys.cpp b/src/VBox/VMM/VMMR3/PGMPhys.cpp
index 9a21f28..80b10ec 100644
--- a/src/VBox/VMM/VMMR3/PGMPhys.cpp
+++ b/src/VBox/VMM/VMMR3/PGMPhys.cpp
@@ -3852,7 +3852,7 @@ VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
     if (pVCpu->pgm.s.fA20Enabled != fEnable)
     {
         pVCpu->pgm.s.fA20Enabled = fEnable;
-        pVCpu->pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!fEnable << 20);
+        pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!fEnable << 20);
 #ifdef VBOX_WITH_REM
         REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
 #endif
diff --git a/src/VBox/VMM/VMMR3/PGMPool.cpp b/src/VBox/VMM/VMMR3/PGMPool.cpp
index 97a8bab..6afc27e 100644
--- a/src/VBox/VMM/VMMR3/PGMPool.cpp
+++ b/src/VBox/VMM/VMMR3/PGMPool.cpp
@@ -298,7 +298,7 @@ int pgmR3PoolInit(PVM pVM)
     pPool->aPages[NIL_PGMPOOL_IDX].iModifiedNext    = NIL_PGMPOOL_IDX;
     pPool->aPages[NIL_PGMPOOL_IDX].iModifiedPrev    = NIL_PGMPOOL_IDX;
     pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredNext   = NIL_PGMPOOL_IDX;
-    pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredNext   = NIL_PGMPOOL_IDX;
+    pPool->aPages[NIL_PGMPOOL_IDX].iMonitoredPrev   = NIL_PGMPOOL_IDX;
     pPool->aPages[NIL_PGMPOOL_IDX].iAgeNext         = NIL_PGMPOOL_IDX;
     pPool->aPages[NIL_PGMPOOL_IDX].iAgePrev         = NIL_PGMPOOL_IDX;
 
@@ -480,7 +480,7 @@ VMMR3DECL(int) PGMR3PoolGrow(PVM pVM)
         pPage->iModifiedNext  = NIL_PGMPOOL_IDX;
         pPage->iModifiedPrev  = NIL_PGMPOOL_IDX;
         pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
-        pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
+        pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
         pPage->iAgeNext  = NIL_PGMPOOL_IDX;
         pPage->iAgePrev  = NIL_PGMPOOL_IDX;
         /* commit it */
diff --git a/src/VBox/VMM/VMMR3/PGMSavedState.cpp b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
index fbd01bb..0d0d30e 100644
--- a/src/VBox/VMM/VMMR3/PGMSavedState.cpp
+++ b/src/VBox/VMM/VMMR3/PGMSavedState.cpp
@@ -3074,7 +3074,11 @@ static int pgmR3LoadFinalLocked(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion)
      * Fix the A20 mask.
      */
     for (VMCPUID i = 0; i < pVM->cCpus; i++)
-        pVM->aCpus[i].pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!pVM->aCpus[i].pgm.s.fA20Enabled << 20);
+    {
+        PVMCPU pVCpu = &pVM->aCpus[i];
+        pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!pVCpu->pgm.s.fA20Enabled << 20);
+        pgmR3RefreshShadowModeAfterA20Change(pVCpu);
+    }
 
     /*
      * The guest mappings - skipped now, see re-fixation in the caller.
diff --git a/src/VBox/VMM/VMMR3/STAM.cpp b/src/VBox/VMM/VMMR3/STAM.cpp
index 6b47ef6..68f7224 100644
--- a/src/VBox/VMM/VMMR3/STAM.cpp
+++ b/src/VBox/VMM/VMMR3/STAM.cpp
@@ -1129,7 +1129,7 @@ static void stamR3LookupMaybeFree(PSTAMLOOKUP pLookup)
     if (pCur->cDescsInTree > 0)
         return;
     PSTAMLOOKUP pParent = pCur->pParent;
-    if (pParent)
+    if (!pParent)
         return;
 
     if (pParent->cDescsInTree == 0 && pParent->pParent)
@@ -1150,6 +1150,7 @@ static void stamR3LookupMaybeFree(PSTAMLOOKUP pLookup)
         papChildren[i] = pChild;
     }
     pCur->pParent = NULL;
+    pCur->iParent = UINT16_MAX;
 
     /*
      * Destroy pCur.
diff --git a/src/VBox/VMM/testcase/tstAnimate.cpp b/src/VBox/VMM/testcase/tstAnimate.cpp
index 1efb09f..ba8eea1 100644
--- a/src/VBox/VMM/testcase/tstAnimate.cpp
+++ b/src/VBox/VMM/testcase/tstAnimate.cpp
@@ -309,7 +309,7 @@ static DECLCALLBACK(int) loadMem(PVM pVM, RTFILE File, uint64_t *poff)
             }
 
             /* Write that page to the guest - skip known rom areas for now. */
-            if (GCPhys < 0xa0000 || GCPhys >= 0x10000) /* ASSUME size of a8Page is a power of 2. */
+            if (GCPhys < 0xa0000 || GCPhys >= 0x100000) /* ASSUME size of a8Page is a power of 2. */
                 PGMPhysWrite(pVM, GCPhys, &au8Page, cbRead);
             GCPhys += cbRead;
         }
diff --git a/src/bldprogs/VBoxCPP.cpp b/src/bldprogs/VBoxCPP.cpp
index 7cc0817..5e0a567 100644
--- a/src/bldprogs/VBoxCPP.cpp
+++ b/src/bldprogs/VBoxCPP.cpp
@@ -1132,7 +1132,7 @@ static void vbcppProcessSkipWhiteAndEscapedEol(PSCMSTREAM pStrmInput)
         }
         else if (RT_C_IS_SPACE(ch))
         {
-            ch = chPrev;
+            chPrev = ch;
             ch = ScmStreamGetCh(pStrmInput);
             Assert(ch == chPrev);
         }
@@ -5359,7 +5359,7 @@ static RTEXITCODE vbcppParseOptions(PVBCPP pThis, int argc, char **argv, bool *p
             case 'V':
             {
                 /* The following is assuming that svn does it's job here. */
-                static const char s_szRev[] = "$Revision: 79724 $";
+                static const char s_szRev[] = "$Revision: 96257 $";
                 const char *psz = RTStrStripL(strchr(s_szRev, ' '));
                 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz);
                 *pfExit = true;
diff --git a/src/bldprogs/scmdiff.cpp b/src/bldprogs/scmdiff.cpp
index 28463ad..f2d28e8 100644
--- a/src/bldprogs/scmdiff.cpp
+++ b/src/bldprogs/scmdiff.cpp
@@ -236,7 +236,7 @@ DECLINLINE(bool) scmDiffCompare(PSCMDIFFSTATE pState,
         || memcmp(pchLeft, pchRight, cchLeft))
     {
         if (   pState->fIgnoreTrailingWhite
-            || pState->fIgnoreTrailingWhite)
+            || pState->fIgnoreLeadingWhite)
             return scmDiffCompareSlow(pState,
                                       pchLeft, cchLeft, enmEolLeft,
                                       pchRight, cchRight, enmEolRight);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/virtualbox.git



More information about the Pkg-virtualbox-commits mailing list