summaryrefslogtreecommitdiff
path: root/src/VBox/HostDrivers
diff options
context:
space:
mode:
authorMichael Meskes <meskes@debian.org>2009-02-09 17:42:08 +0100
committerMichael Meskes <meskes@debian.org>2009-02-09 17:42:08 +0100
commit5b633c860b9ccb98910812f91c2474fda316b50b (patch)
treedb6656e828509048e53ad8aea69d2edb9f64f442 /src/VBox/HostDrivers
parentce414e6eec1583def0dc7be0926f1a07364cb5e3 (diff)
downloadvirtualbox-5b633c860b9ccb98910812f91c2474fda316b50b.tar.gz
Imported 2.1.2-dfsgupstream/2.1.2-dfsg
Diffstat (limited to 'src/VBox/HostDrivers')
-rw-r--r--src/VBox/HostDrivers/Makefile.kmk55
-rw-r--r--src/VBox/HostDrivers/Support/Makefile.kmk434
-rw-r--r--src/VBox/HostDrivers/Support/SUPDrv.c4810
-rw-r--r--src/VBox/HostDrivers/Support/SUPDrvIDC.h276
-rw-r--r--src/VBox/HostDrivers/Support/SUPDrvIOC.h988
-rw-r--r--src/VBox/HostDrivers/Support/SUPDrvInternal.h641
-rw-r--r--src/VBox/HostDrivers/Support/SUPLib.cpp1928
-rw-r--r--src/VBox/HostDrivers/Support/SUPLibInternal.h324
-rw-r--r--src/VBox/HostDrivers/Support/SUPR0.def129
-rw-r--r--src/VBox/HostDrivers/Support/SUPR0IdcClient.c214
-rw-r--r--src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c94
-rw-r--r--src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h88
-rw-r--r--src/VBox/HostDrivers/Support/SUPR0IdcClientStubs.c147
-rw-r--r--src/VBox/HostDrivers/Support/SUPR3HardenedIPRT.cpp160
-rw-r--r--src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp1068
-rw-r--r--src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp810
-rw-r--r--src/VBox/HostDrivers/Support/SUPSvc.cpp450
-rw-r--r--src/VBox/HostDrivers/Support/SUPSvcGlobal.cpp72
-rw-r--r--src/VBox/HostDrivers/Support/SUPSvcGrant.cpp1005
-rw-r--r--src/VBox/HostDrivers/Support/SUPSvcInternal.h95
-rw-r--r--src/VBox/HostDrivers/Support/darwin/Info-Tiger.plist39
-rw-r--r--src/VBox/HostDrivers/Support/darwin/Info.plist39
-rw-r--r--src/VBox/HostDrivers/Support/darwin/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp1126
-rw-r--r--src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp304
-rw-r--r--src/VBox/HostDrivers/Support/darwin/SUPR0IdcClient-darwin.c59
-rw-r--r--src/VBox/HostDrivers/Support/freebsd/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c586
-rw-r--r--src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp196
-rw-r--r--src/VBox/HostDrivers/Support/freebsd/SUPR0IdcClient-freebsd.c59
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile282
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c1089
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c94
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp255
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c59
-rw-r--r--src/VBox/HostDrivers/Support/linux/dkms.conf6
-rw-r--r--src/VBox/HostDrivers/Support/linux/files_vboxdrv129
-rw-r--r--src/VBox/HostDrivers/Support/os2/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp425
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPDrv-os2.def48
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm974
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp197
-rw-r--r--src/VBox/HostDrivers/Support/os2/SUPR0IdcClient-os2.c54
-rw-r--r--src/VBox/HostDrivers/Support/solaris/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c889
-rw-r--r--src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp190
-rw-r--r--src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c59
-rwxr-xr-xsrc/VBox/HostDrivers/Support/solaris/mod.sh76
-rw-r--r--src/VBox/HostDrivers/Support/solaris/vboxdrv.conf25
-rw-r--r--src/VBox/HostDrivers/Support/testcase/Makefile.kmk83
-rw-r--r--src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp53
-rw-r--r--src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp53
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp104
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp185
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp99
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstInit.cpp55
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstInt.cpp233
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstLow.cpp159
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstPage.cpp96
-rw-r--r--src/VBox/HostDrivers/Support/testcase/tstPin.cpp213
-rw-r--r--src/VBox/HostDrivers/Support/win/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp652
-rw-r--r--src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm328
-rw-r--r--src/VBox/HostDrivers/Support/win/SUPLib-win.cpp599
-rw-r--r--src/VBox/HostDrivers/Support/win/SUPR0IdcClient-win.c160
-rw-r--r--src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp900
-rw-r--r--src/VBox/HostDrivers/Support/win/VBoxDrv.inf73
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk314
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c1341
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h424
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/darwin/Info.plist32
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/darwin/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp1183
-rwxr-xr-xsrc/VBox/HostDrivers/VBoxNetFlt/darwin/loadnetflt.sh114
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile264
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c1099
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/linux/dkms.conf7
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/linux/files_vboxnetflt137
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c3319
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/solaris/vboxflt.conf25
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/Makefile.kmk83
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/VBoxTAP.inf164
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/common.h77
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/config-win32.h309
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/constants.h55
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/dhcp.c603
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/dhcp.h168
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/endian.h39
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/error.c382
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/error.h103
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/hexdump.c74
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/hexdump.h68
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/instance.c245
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/lock.h79
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/macinfo.c159
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/macinfo.h43
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/mem.c190
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/proto.h168
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/prototypes.h206
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/tapdrvr.c2793
-rw-r--r--src/VBox/HostDrivers/VBoxTAP/types.h163
-rw-r--r--src/VBox/HostDrivers/linux/Makefile64
-rw-r--r--src/VBox/HostDrivers/linux/Makefile.kup0
-rwxr-xr-xsrc/VBox/HostDrivers/linux/build_in_tmp112
-rwxr-xr-xsrc/VBox/HostDrivers/linux/export_modules103
107 files changed, 39801 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/Makefile.kmk b/src/VBox/HostDrivers/Makefile.kmk
new file mode 100644
index 000000000..1dae601fa
--- /dev/null
+++ b/src/VBox/HostDrivers/Makefile.kmk
@@ -0,0 +1,55 @@
+# $Id: Makefile.kmk 14545 2008-11-24 21:15:01Z vboxsync $
+## @file
+# Top-level makefile for the VBox Host drivers.
+#
+
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SUB_DEPTH = ../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# Include sub-makefiles.
+include $(PATH_SUB_CURRENT)/Support/Makefile.kmk
+
+ifndef VBOX_ONLY_DOCS
+ ifeq ($(KBUILD_TARGET),win)
+ include $(PATH_SUB_CURRENT)/VBoxTAP/Makefile.kmk
+ endif
+ ifdef VBOX_WITH_USB
+ include $(PATH_SUB_CURRENT)/VBoxUSB/Makefile.kmk
+ endif
+ if1of ($(KBUILD_TARGET), darwin solaris win linux)
+ ifdef VBOX_WITH_NETFLT
+ include $(PATH_SUB_CURRENT)/VBoxNetFlt/Makefile.kmk
+ endif
+ endif
+
+ ifeq ($(KBUILD_TARGET),linux)
+ #
+ # Install the Makefile for module compliation on Linux hosts
+ #
+ INSTALLS += HostDrivers-src
+ HostDrivers-src_INST = bin/src/
+ HostDrivers-src_MODE = a+r,u+w
+ HostDrivers-src_SOURCES = linux/Makefile
+ endif
+
+endif # !VBOX_ONLY_DOCS
+
+# Let kBuild generate the rules.
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/HostDrivers/Support/Makefile.kmk b/src/VBox/HostDrivers/Support/Makefile.kmk
new file mode 100644
index 000000000..7333bf284
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/Makefile.kmk
@@ -0,0 +1,434 @@
+# $Id: Makefile.kmk 15589 2008-12-16 14:24:08Z vboxsync $
+## @file
+# Sub-Makefile for the support library and the drivers/modules/kexts it uses.
+#
+
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# Targets
+#
+LIBRARIES += SUPR3 SUPR3HardenedStatic
+ifndef VBOX_ONLY_DOCS
+ ifeq ($(filter-out pe lx,$(VBOX_LDR_FMT)),)
+ LIBRARIES += SUPR0
+ endif
+ ifdef VBOX_WITH_SUPSVC
+ PROGRAMS += VBoxSupSvc
+ endif
+ ifdef VBOX_WITH_VBOXDRV
+ LIBRARIES += SUPR0IdcClient
+ SYSMODS.freebsd += vboxdrv
+ SYSMODS.linux += vboxdrv
+ SYSMODS.win += VBoxDrv
+ SYSMODS.os2 += VBoxDrv
+ SYSMODS.solaris += vboxdrv
+ endif
+ INSTALLS.linux += vboxdrv-mod vboxdrv-sh
+
+ #
+ # Include sub-makefile(s).
+ #
+ include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
+
+ #
+ # Populate FILES_VBOXDRV_NOBIN and FILES_VBOXDRV_BIN
+ #
+ include $(PATH_SUB_CURRENT)/linux/files_vboxdrv
+endif # !VBOX_ONLY_DOCS
+
+
+#
+# The Ring-3 Support Library (this is linked into the IPRT dll, VBoxRT).
+#
+ifneq ($(filter l4%,$(KBUILD_TARGET) $(BUILD_TARGET_SUB)),)
+ # L4 has trouble with -pedantic. It also make trouble when inlining is not enabled.
+ SUPR3_TEMPLATE = VBOXR3NP
+else
+ SUPR3_TEMPLATE = VBOXR3
+endif
+SUPR3_DEFS = IN_SUP_R3 IN_RT_R3
+ifdef VBOX_WITH_SUPSVC
+ SUPR3_DEFS += VBOX_WITH_SUPSVC
+endif
+SUPR3_INCS := $(PATH_SUB_CURRENT)
+SUPR3_INCS.l4 = $(L4_INCDIR)
+SUPR3_SOURCES = \
+ SUPLib.cpp \
+ SUPR3HardenedIPRT.cpp \
+ SUPR3HardenedVerify.cpp \
+ $(KBUILD_TARGET)/SUPLib-$(KBUILD_TARGET).cpp
+
+
+#
+# The static part of the hardened support library (ring-3).
+#
+SUPR3HardenedStatic_TEMPLATE = VBOXR3HARDENEDLIB
+SUPR3HardenedStatic_DEFS = IN_SUP_HARDENED_R3
+ifdef VBOX_WITH_SUPSVC
+ SUPR3HardenedStatic_DEFS += VBOX_WITH_SUPSVC
+endif
+SUPR3HardenedStatic_INCS = .
+SUPR3HardenedStatic_SOURCES = \
+ SUPR3HardenedMain.cpp \
+ SUPR3HardenedVerify.cpp \
+ $(KBUILD_TARGET)/SUPLib-$(KBUILD_TARGET).cpp
+
+ifndef VBOX_ONLY_DOCS
+
+#
+# VBoxSupSvc - The system wide service/daemon.
+#
+VBoxSupSvc_TEMPLATE = VBOXR3EXE
+VBoxSupSvc_SOURCES = \
+ SUPSvc.cpp \
+ SUPSvcGlobal.cpp \
+ $(KBUILD_TARGET)/SUPSvc-$(KBUILD_TARGET).cpp
+if1of ($(KBUILD_TARGET), win)
+ VBoxSupSvc_SOURCES += \
+ SUPSvcGrant.cpp
+endif
+ifn1of ($(KBUILD_TARGET), win)
+ VBoxSupSvc_SOURCES += \
+ SUPSvcMain-posix.cpp
+endif
+VBoxSupSvc_LIBS = \
+ $(LIB_RUNTIME)
+
+
+#
+# SUPR0 - The Ring-0 Import / Thunk library.
+#
+SUPR0_TEMPLATE = VBOXR0
+ifeq ($(VBOX_LDR_FMT),pe)
+ SUPR0_SOURCES += SUPR0.def
+endif
+ifeq ($(VBOX_LDR_FMT),lx)
+SUPR0_SOURCES += $$(PATH_SUPR0)/SUPR0.def
+$$(PATH_SUPR0)/SUPR0.def: $(PATH_SUB_CURRENT)/SUPR0.def | $$(dir $$@)
+ $(SED) -e 's/^[ \t][ \t]*\([gA-Z]\)/ _\1/' -e 's/[ \t]DATA[ \t]*/ /' $< > $@.tmp
+ $(MV) -f $@.tmp $@
+endif
+
+
+#
+# SUPR0IdcClient - The Ring-0 IDC client driver library.
+#
+SUPR0IdcClient_TEMPLATE = VBOXR0DRV
+SUPR0IdcClient_DEFS = IN_RT_R0 IN_SUP_R0 IN_SUP_STATIC
+SUPR0IdcClient_SDKS.win = W2K3DDK WINPSDKINCS
+SUPR0IdcClient_SOURCES.$(KBUILD_TARGET) = \
+ $(KBUILD_TARGET)/SUPR0IdcClient-$(KBUILD_TARGET).c
+SUPR0IdcClient_SOURCES = \
+ SUPR0IdcClient.c \
+ SUPR0IdcClientComponent.c \
+ SUPR0IdcClientStubs.c
+
+
+#
+# VBoxDrv.sys - The Windows driver.
+#
+## @todo consoliate all the targets into a single mess.
+ifeq ($(KBUILD_TARGET),win)
+VBoxDrv_TEMPLATE = VBOXR0DRV
+ifdef VBOX_SIGNING_MODE
+ VBoxDrv_NOINST = true
+endif
+VBoxDrv_DEFS = IN_RT_R0 IN_SUP_R0 SUPDRV_WITH_RELEASE_LOGGER
+VBoxDrv_DEFS.amd64 = RT_WITH_W64_UNWIND_HACK
+VBoxDrv_SDKS = W2K3DDK WINPSDKINCS
+VBoxDrv_INCS := $(PATH_SUB_CURRENT)
+VBoxDrv_SOURCES = \
+ win/SUPDrv-win.cpp \
+ win/SUPDrvA-win.asm \
+ SUPDrv.c
+VBoxDrv_LDFLAGS.x86 = -Entry:DriverEntry@8
+VBoxDrv_LDFLAGS.amd64 = -Entry:DriverEntry
+VBoxDrv_LIBS = \
+ $(PATH_SDK_W2K3DDK_LIB)/ntoskrnl.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/hal.lib \
+ $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+
+
+INSTALLS += VBoxDrv-inf
+VBoxDrv-inf_INST = $(INST_BIN)
+VBoxDrv-inf_MODE = a+r,u+w
+VBoxDrv-inf_SOURCES = \
+ $(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.inf
+VBoxDrv-inf_CLEAN = $(VBoxDrv-inf_SOURCES)
+VBoxDrv-inf_BLDDIRS = $(PATH_TARGET)/VBoxDrvCat.dir
+
+$(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.inf: $(PATH_SUB_CURRENT)/win/VBoxDrv.inf $(MAKEFILE_CURRENT) | $$(call DIRDEP,$$(@D))
+ $(call MSG_GENERATE,VBoxDrv-inf,$@,$<)
+ $(call VBOX_EDIT_INF_FN,$<,$@)
+
+ ifdef VBOX_SIGNING_MODE
+VBoxDrv-inf_SOURCES += \
+ $(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.sys \
+ $(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.cat
+
+$(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.sys: $$(TARGET_VBoxDrv) | $$(call DIRDEP,$$(@D))
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.cat: \
+ $(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.inf \
+ $(PATH_TARGET)/VBoxDrvCat.dir/VBoxDrv.sys
+ $(call MSG_TOOL,Inf2Cat,VBoxDrv-inf,$@,$<)
+ $(call VBOX_MAKE_CAT_FN, $(@D),$@)
+ endif # signing
+endif # win
+
+
+#
+# vboxdrv.ko - The Linux Kernel Module (syntax check only).
+#
+ifeq ($(KBUILD_TARGET),linux)
+vboxdrv_TEMPLATE = VBOXR0DRV
+vboxdrv_NOINST = true
+vboxdrv_DEFS = KBUILD_MODNAME=KBUILD_STR\(vboxdrv\) KBUILD_BASENAME=KBUILD_STR\(vboxdrv\) MODULE IN_RT_R0 IN_SUP_R0 CONFIG_VBOXDRV_AS_MISC
+ifdef VBOX_LINUX_VERSION_2_4
+vboxdrv_DEFS += EXPORT_SYMTAB
+endif
+vboxdrv_INCS := \
+ $(PATH_SUB_CURRENT) \
+ $(PATH_ROOT)/src/VBox/Runtime/r0drv/linux
+vboxdrv_LIBS = $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+vboxdrv_LIBS.debug = $(vboxdrv_LIBS) $(VBOX_GCC_LIBGCC)
+vboxdrv_SOURCES = \
+ $(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).c \
+ SUPDrv.c
+ifndef VBOX_LINUX_VERSION_2_4
+vboxdrv_SOURCES += \
+ $(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).mod.c
+endif
+
+
+#
+# Targets for installing the linux sources.
+#
+vboxdrv-mod_INST = bin/src/vboxdrv/
+vboxdrv-mod_MODE = a+r,u+w
+vboxdrv-mod_SOURCES = $(subst ",,$(FILES_VBOXDRV_NOBIN)) #"
+vboxdrv-mod_SOURCES += \
+ $(if $(VBOX_OSE),,\
+ $(PATH_vboxdrv-mod)/dkms.conf) \
+ $(PATH_vboxdrv-mod)/Makefile
+vboxdrv-mod_CLEAN = \
+ $(PATH_vboxdrv-mod)/dkms.conf \
+ $(PATH_vboxdrv-mod)/Makefile
+
+vboxdrv-sh_INST = bin/src/vboxdrv
+vboxdrv-sh_MODE = a+rx,u+w
+vboxdrv-sh_SOURCES = $(subst ",,$(FILES_VBOXDRV_BIN)) #"
+vboxdrv-sh_SOURCES += \
+ $(PATH_vboxdrv-sh)/build_in_tmp \
+ $(if $(VBOX_OSE),,\
+ $(PATH_ROOT)/src/VBox/HostDrivers/linux/do_Module.symvers)
+vboxdrv-sh_CLEAN = \
+ $(PATH_TARGET)/vboxdrv-sh-1.dep \
+ $(PATH_vboxdrv-sh)/build_in_tmp
+
+
+# Scripts needed for building the kernel modules
+
+$$(PATH_vboxdrv-sh)/build_in_tmp: \
+ $(PATH_ROOT)/src/VBox/HostDrivers/linux/build_in_tmp \
+ $(VBOX_VERSION_STAMP) \
+ | $$(dir $$@)
+ $(call MSG_TOOL,Creating,,$@)
+ $(QUIET)$(SED) -e "s;_VERSION_;${VBOX_VERSION_STRING};g; s;_MODULE_;vboxdrv;g" --output $@ $<
+ $(QUIET)chmod 0755 $@
+
+$$(PATH_vboxdrv-mod)/dkms.conf: \
+ $(PATH_SUB_CURRENT)/linux/dkms.conf \
+ $(VBOX_VERSION_STAMP) \
+ | $$(dir $$@)
+ $(call MSG_TOOL,Creating,,$@)
+ $(QUIET)$(SED) -e "s;_VERSION_;${VBOX_VERSION_STRING};g" --output $@ $<
+
+includedep $(PATH_TARGET)/vboxdrv-sh-1.dep
+$$(PATH_vboxdrv-mod)/Makefile: \
+ $(PATH_SUB_CURRENT)/linux/Makefile \
+ $$(if $$(eq $$(Support/linux/Makefile_VBOX_HARDENED),$$(VBOX_WITH_HARDENING)),,FORCE) \
+ | $$(dir $$@)
+ $(call MSG_TOOL,Creating,,$@)
+ ifndef VBOX_WITH_HARDENING
+ $(QUIET)$(SED) -e "s;-DVBOX_WITH_HARDENING;;g" --output $@ $<
+ else
+ $(QUIET)$(CP) -f $< $@
+ endif
+ %$(QUIET2)$(RM) -f -- $(PATH_TARGET)/vboxdrv-sh-1.dep
+ %$(QUIET2)$(APPEND) '$(PATH_TARGET)/vboxdrv-sh-1.dep' 'Support/linux/Makefile_VBOX_HARDENED=$(VBOX_WITH_HARDENING)'
+
+endif # real linux
+
+
+
+
+#
+# VBoxDrv.kext - The Darwin Kernel Extension.
+#
+ifeq ($(KBUILD_TARGET),darwin)
+# The Tiger variant.
+SYSMODS += VBoxDrvTiger
+VBoxDrvTiger_TEMPLATE = VBOXR0DRV
+VBoxDrvTiger_INST = $(INST_VBOXDRV_TIGER)Contents/MacOS/
+VBoxDrvTiger_DEFS := IN_RT_R0 IN_SUP_R0 SUPDRV_WITH_RELEASE_LOGGER VBOX_SVN_REV=$(VBOX_SVN_REV)
+VBoxDrvTiger_DEFS.debug += DEBUG_DARWIN_GIP
+VBoxDrvTiger_INCS = .
+VBoxDrvTiger_LIBS = $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+VBoxDrvTiger_LDFLAGS = -v -Wl,-whyload -Wl,-v -Wl,-whatsloaded
+VBoxDrvTiger_SOURCES = \
+ SUPDrv.c \
+ $(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).cpp
+
+INSTALLS += VBoxDrvTiger.kext
+VBoxDrvTiger.kext_INST = $(INST_VBOXDRV_TIGER)Contents/
+VBoxDrvTiger.kext_SOURCES = $(PATH_VBoxDrvTiger.kext)/Info.plist
+VBoxDrvTiger.kext_CLEAN = $(PATH_VBoxDrvTiger.kext)/Info.plist
+
+$$(PATH_VBoxDrvTiger.kext)/Info.plist: $(PATH_SUB_CURRENT)/darwin/Info-Tiger.plist $(VBOX_VERSION_MK) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxDrvTiger,$@,$<)
+ $(xQUIET)$(RM) -f $@
+ $(xQUIET)$(SED) \
+ -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/g' \
+ -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/g' \
+ -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/g' \
+ -e 's/@VBOX_VERSION_BUILD@/$(VBOX_VERSION_BUILD)/g' \
+ --output $@ \
+ $<
+
+# The Leopard variant.
+SYSMODS += VBoxDrv
+VBoxDrv_EXTENDS = VBoxDrvTiger
+VBoxDrv_EXTENDS_BY = appending
+VBoxDrv_TEMPLATE = VBOXR0DRVOSX105
+VBoxDrv_INST = $(INST_VBOXDRV)Contents/MacOS/
+VBoxDrv_DEFS = VBOX_WITH_HOST_VMX
+
+INSTALLS += VBoxDrv.kext
+VBoxDrv.kext_INST = $(INST_VBOXDRV)Contents/
+VBoxDrv.kext_SOURCES = $(PATH_VBoxDrv.kext)/Info.plist
+VBoxDrv.kext_CLEAN = $(PATH_VBoxDrv.kext)/Info.plist
+
+$$(PATH_VBoxDrv.kext)/Info.plist: $(PATH_SUB_CURRENT)/darwin/Info.plist $(VBOX_VERSION_MK) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxDrv,$@,$<)
+ $(xQUIET)$(RM) -f $@
+ $(xQUIET)$(SED) \
+ -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/g' \
+ -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/g' \
+ -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/g' \
+ -e 's/@VBOX_VERSION_BUILD@/$(VBOX_VERSION_BUILD)/g' \
+ --output $@ \
+ $<
+
+# Common manual loader script.
+INSTALLS += Scripts
+Scripts_INST = $(INST_DIST)
+Scripts_SOURCES = \
+ darwin/load.sh
+
+endif # darwin
+
+
+#
+# VBoxDrv.sys - The OS/2 driver.
+#
+ifeq ($(KBUILD_TARGET),os2)
+VBoxDrv_TEMPLATE = VBOXR0DRV
+VBoxDrv_DEFS = IN_RT_R0 IN_SUP_R0
+VBoxDrv_INCS := $(PATH_SUB_CURRENT)
+#VBoxDrv_LDFLAGS = -s -t -v
+VBoxDrv_SOURCES = \
+ os2/SUPDrvA-os2.asm \
+ os2/SUPDrv-os2.def
+VBoxDrv_LIBS = \
+ $(TARGET_VBoxDrvLib) \
+ $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB) \
+ $(VBOX_GCC_LIBGCC) \
+ end
+
+# temp hack to ensure that SUPDrvA-os2.asm is first in the link.
+LIBRARIES += VBoxDrvLib
+VBoxDrvLib_TEMPLATE = VBOXR0DRV
+VBoxDrvLib_NOINST = 1
+VBoxDrvLib_DEFS = IN_RT_R0 IN_SUP_R0
+VBoxDrvLib_INCS := \
+ . \
+ $(PATH_ROOT)/src/VBox/Runtime/include
+VBoxDrvLib_SOURCES = \
+ os2/SUPDrv-os2.cpp \
+ SUPDrv.c
+endif
+
+
+#
+# vboxdrv.ko - The FreeBSD Kernel Module.
+#
+ifeq ($(KBUILD_TARGET),freebsd)
+vboxdrv_TEMPLATE = VBOXR0DRV
+vboxdrv_DEFS = IN_RT_R0 IN_SUP_R0 SUPDRV_WITH_RELEASE_LOGGER VBOX_SVN_REV=$(VBOX_SVN_REV)
+vboxdrv_INCS := $(PATH_SUB_CURRENT)
+vboxdrv_LIBS = $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+vboxdrv_SOURCES := \
+ $(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).c \
+ $(PATH_SUB_CURRENT)/$(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).def \
+ SUPDrv.c
+## @todo the SUPDrv-freebsd.def is most probably gonna break it and require build system hacking...
+endif # freebsd
+
+
+#
+# vboxdrv.o - The Solaris Kernel Module.
+#
+ifeq ($(KBUILD_TARGET),solaris)
+vboxdrv_TEMPLATE = VBOXR0DRV
+vboxdrv_DEFS = IN_RT_R0 IN_SUP_R0 SUPDRV_WITH_RELEASE_LOGGER
+ifdef VBOX_WITH_NETFLT
+ vboxdrv_DEFS += VBOX_WITH_NETFLT
+endif
+vboxdrv_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+vboxdrv_DEPS += $(VBOX_SVN_REV_KMK)
+vboxdrv_INCS := $(PATH_SUB_CURRENT)
+vboxdrv_LIBS = $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+vboxdrv_SOURCES = \
+ $(KBUILD_TARGET)/SUPDrv-$(KBUILD_TARGET).c \
+ SUPDrv.c
+endif # solaris
+
+
+#
+# SUPDrv.c needs the VBOX_SVN_REV.
+#
+SUPDrv.c_DEFS += VBOX_SVN_REV=$(VBOX_SVN_REV)
+
+
+endif # !VBOX_ONLY_DOCS
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/HostDrivers/Support/SUPDrv.c b/src/VBox/HostDrivers/Support/SUPDrv.c
new file mode 100644
index 000000000..4e7fbe908
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPDrv.c
@@ -0,0 +1,4810 @@
+/* $Revision: 15843 $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Common code.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#include "SUPDrvInternal.h"
+#ifndef PAGE_SHIFT
+# include <iprt/param.h>
+#endif
+#include <iprt/alloc.h>
+#include <iprt/semaphore.h>
+#include <iprt/spinlock.h>
+#include <iprt/thread.h>
+#include <iprt/process.h>
+#include <iprt/mp.h>
+#include <iprt/power.h>
+#include <iprt/cpuset.h>
+#include <iprt/uuid.h>
+#include <VBox/param.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+# include <iprt/crc32.h>
+# include <iprt/net.h>
+#endif
+/* VBox/x86.h not compatible with the Linux kernel sources */
+#ifdef RT_OS_LINUX
+# define X86_CPUID_VENDOR_AMD_EBX 0x68747541
+# define X86_CPUID_VENDOR_AMD_ECX 0x444d4163
+# define X86_CPUID_VENDOR_AMD_EDX 0x69746e65
+#else
+# include <VBox/x86.h>
+#endif
+
+/*
+ * Logging assignments:
+ * Log - useful stuff, like failures.
+ * LogFlow - program flow, except the really noisy bits.
+ * Log2 - Cleanup.
+ * Log3 - Loader flow noise.
+ * Log4 - Call VMMR0 flow noise.
+ * Log5 - Native yet-to-be-defined noise.
+ * Log6 - Native ioctl flow noise.
+ *
+ * Logging requires BUILD_TYPE=debug and possibly changes to the logger
+ * instanciation in log-vbox.c(pp).
+ */
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/* from x86.h - clashes with linux thus this duplication */
+#undef X86_CR0_PG
+#define X86_CR0_PG RT_BIT(31)
+#undef X86_CR0_PE
+#define X86_CR0_PE RT_BIT(0)
+#undef X86_CPUID_AMD_FEATURE_EDX_NX
+#define X86_CPUID_AMD_FEATURE_EDX_NX RT_BIT(20)
+#undef MSR_K6_EFER
+#define MSR_K6_EFER 0xc0000080
+#undef MSR_K6_EFER_NXE
+#define MSR_K6_EFER_NXE RT_BIT(11)
+#undef MSR_K6_EFER_LMA
+#define MSR_K6_EFER_LMA RT_BIT(10)
+#undef X86_CR4_PGE
+#define X86_CR4_PGE RT_BIT(7)
+#undef X86_CR4_PAE
+#define X86_CR4_PAE RT_BIT(5)
+#undef X86_CPUID_AMD_FEATURE_EDX_LONG_MODE
+#define X86_CPUID_AMD_FEATURE_EDX_LONG_MODE RT_BIT(29)
+
+
+/** The frequency by which we recalculate the u32UpdateHz and
+ * u32UpdateIntervalNS GIP members. The value must be a power of 2. */
+#define GIP_UPDATEHZ_RECALC_FREQ 0x800
+
+/**
+ * Validates a session pointer.
+ *
+ * @returns true/false accordingly.
+ * @param pSession The session.
+ */
+#define SUP_IS_SESSION_VALID(pSession) \
+ ( VALID_PTR(pSession) \
+ && pSession->u32Cookie == BIRD_INV)
+
+/** @def VBOX_SVN_REV
+ * The makefile should define this if it can. */
+#ifndef VBOX_SVN_REV
+# define VBOX_SVN_REV 0
+#endif
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession);
+static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType);
+static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq);
+static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq);
+static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq);
+static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq);
+static int supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq);
+static int supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx);
+static void supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt);
+static int supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage);
+static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage);
+static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPCALLSERVICE pReq);
+static SUPGIPMODE supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt);
+#ifdef RT_OS_WINDOWS
+static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
+static bool supdrvPageWasLockedByPageAlloc(PSUPDRVSESSION pSession, RTR3PTR pvR3);
+#endif /* RT_OS_WINDOWS */
+static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt);
+static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt);
+static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
+static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
+static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
+
+#ifdef RT_WITH_W64_UNWIND_HACK
+DECLASM(int) supdrvNtWrapVMMR0EntryEx(PFNRT pfnVMMR0EntryEx, PVM pVM, unsigned uOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession);
+DECLASM(int) supdrvNtWrapVMMR0EntryFast(PFNRT pfnVMMR0EntryFast, PVM pVM, unsigned idCpu, unsigned uOperation);
+DECLASM(void) supdrvNtWrapObjDestructor(PFNRT pfnDestruction, void *pvObj, void *pvUser1, void *pvUser2);
+DECLASM(void *) supdrvNtWrapQueryFactoryInterface(PFNRT pfnQueryFactoryInterface, struct SUPDRVFACTORY const *pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid);
+DECLASM(int) supdrvNtWrapModuleInit(PFNRT pfnModuleInit);
+DECLASM(void) supdrvNtWrapModuleTerm(PFNRT pfnModuleTerm);
+DECLASM(int) supdrvNtWrapServiceReqHandler(PFNRT pfnServiceReqHandler, PSUPDRVSESSION pSession, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr);
+
+DECLASM(int) UNWIND_WRAP(SUPR0ComponentRegisterFactory)(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory);
+DECLASM(int) UNWIND_WRAP(SUPR0ComponentDeregisterFactory)(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory);
+DECLASM(int) UNWIND_WRAP(SUPR0ComponentQueryFactory)(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf);
+DECLASM(void *) UNWIND_WRAP(SUPR0ObjRegister)(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2);
+DECLASM(int) UNWIND_WRAP(SUPR0ObjAddRef)(void *pvObj, PSUPDRVSESSION pSession);
+DECLASM(int) UNWIND_WRAP(SUPR0ObjAddRefEx)(void *pvObj, PSUPDRVSESSION pSession, bool fNoPreempt);
+DECLASM(int) UNWIND_WRAP(SUPR0ObjRelease)(void *pvObj, PSUPDRVSESSION pSession);
+DECLASM(int) UNWIND_WRAP(SUPR0ObjVerifyAccess)(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
+DECLASM(int) UNWIND_WRAP(SUPR0LockMem)(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
+DECLASM(int) UNWIND_WRAP(SUPR0UnlockMem)(PSUPDRVSESSION pSession, RTR3PTR pvR3);
+DECLASM(int) UNWIND_WRAP(SUPR0ContAlloc)(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys);
+DECLASM(int) UNWIND_WRAP(SUPR0ContFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
+DECLASM(int) UNWIND_WRAP(SUPR0LowAlloc)(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages);
+DECLASM(int) UNWIND_WRAP(SUPR0LowFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
+DECLASM(int) UNWIND_WRAP(SUPR0MemAlloc)(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3);
+DECLASM(int) UNWIND_WRAP(SUPR0MemGetPhys)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages);
+DECLASM(int) UNWIND_WRAP(SUPR0MemFree)(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
+DECLASM(int) UNWIND_WRAP(SUPR0PageAlloc)(PSUPDRVSESSION pSession, uint32_t cPages, PRTR3PTR ppvR3, PRTHCPHYS paPages);
+DECLASM(int) UNWIND_WRAP(SUPR0PageFree)(PSUPDRVSESSION pSession, RTR3PTR pvR3);
+//DECLASM(int) UNWIND_WRAP(SUPR0Printf)(const char *pszFormat, ...);
+DECLASM(SUPPAGINGMODE) UNWIND_WRAP(SUPR0GetPagingMode)(void);
+DECLASM(void *) UNWIND_WRAP(RTMemAlloc)(size_t cb) RT_NO_THROW;
+DECLASM(void *) UNWIND_WRAP(RTMemAllocZ)(size_t cb) RT_NO_THROW;
+DECLASM(void) UNWIND_WRAP(RTMemFree)(void *pv) RT_NO_THROW;
+DECLASM(void *) UNWIND_WRAP(RTMemDup)(const void *pvSrc, size_t cb) RT_NO_THROW;
+DECLASM(void *) UNWIND_WRAP(RTMemDupEx)(const void *pvSrc, size_t cbSrc, size_t cbExtra) RT_NO_THROW;
+DECLASM(void *) UNWIND_WRAP(RTMemRealloc)(void *pvOld, size_t cbNew) RT_NO_THROW;
+DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocLow)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPage)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPhys)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocPhysNC)(PRTR0MEMOBJ pMemObj, size_t cb, RTHCPHYS PhysHighest);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjAllocCont)(PRTR0MEMOBJ pMemObj, size_t cb, bool fExecutable);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjEnterPhys)(PRTR0MEMOBJ pMemObj, RTHCPHYS Phys, size_t cb);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjLockUser)(PRTR0MEMOBJ pMemObj, RTR3PTR R3Ptr, size_t cb, RTR0PROCESS R0Process);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjMapKernel)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjMapKernelEx)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, void *pvFixed, size_t uAlignment, unsigned fProt, size_t offSub, size_t cbSub);
+DECLASM(int) UNWIND_WRAP(RTR0MemObjMapUser)(PRTR0MEMOBJ pMemObj, RTR0MEMOBJ MemObjToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process);
+/*DECLASM(void *) UNWIND_WRAP(RTR0MemObjAddress)(RTR0MEMOBJ MemObj); - not necessary */
+/*DECLASM(RTR3PTR) UNWIND_WRAP(RTR0MemObjAddressR3)(RTR0MEMOBJ MemObj); - not necessary */
+/*DECLASM(size_t) UNWIND_WRAP(RTR0MemObjSize)(RTR0MEMOBJ MemObj); - not necessary */
+/*DECLASM(bool) UNWIND_WRAP(RTR0MemObjIsMapping)(RTR0MEMOBJ MemObj); - not necessary */
+/*DECLASM(RTHCPHYS) UNWIND_WRAP(RTR0MemObjGetPagePhysAddr)(RTR0MEMOBJ MemObj, size_t iPage); - not necessary */
+DECLASM(int) UNWIND_WRAP(RTR0MemObjFree)(RTR0MEMOBJ MemObj, bool fFreeMappings);
+/* RTProcSelf - not necessary */
+/* RTR0ProcHandleSelf - not necessary */
+DECLASM(int) UNWIND_WRAP(RTSemFastMutexCreate)(PRTSEMFASTMUTEX pMutexSem);
+DECLASM(int) UNWIND_WRAP(RTSemFastMutexDestroy)(RTSEMFASTMUTEX MutexSem);
+DECLASM(int) UNWIND_WRAP(RTSemFastMutexRequest)(RTSEMFASTMUTEX MutexSem);
+DECLASM(int) UNWIND_WRAP(RTSemFastMutexRelease)(RTSEMFASTMUTEX MutexSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventCreate)(PRTSEMEVENT pEventSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventSignal)(RTSEMEVENT EventSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventWait)(RTSEMEVENT EventSem, unsigned cMillies);
+DECLASM(int) UNWIND_WRAP(RTSemEventWaitNoResume)(RTSEMEVENT EventSem, unsigned cMillies);
+DECLASM(int) UNWIND_WRAP(RTSemEventDestroy)(RTSEMEVENT EventSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiCreate)(PRTSEMEVENTMULTI pEventMultiSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiSignal)(RTSEMEVENTMULTI EventMultiSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiReset)(RTSEMEVENTMULTI EventMultiSem);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiWait)(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiWaitNoResume)(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies);
+DECLASM(int) UNWIND_WRAP(RTSemEventMultiDestroy)(RTSEMEVENTMULTI EventMultiSem);
+DECLASM(int) UNWIND_WRAP(RTSpinlockCreate)(PRTSPINLOCK pSpinlock);
+DECLASM(int) UNWIND_WRAP(RTSpinlockDestroy)(RTSPINLOCK Spinlock);
+DECLASM(void) UNWIND_WRAP(RTSpinlockAcquire)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
+DECLASM(void) UNWIND_WRAP(RTSpinlockRelease)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
+DECLASM(void) UNWIND_WRAP(RTSpinlockAcquireNoInts)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
+DECLASM(void) UNWIND_WRAP(RTSpinlockReleaseNoInts)(RTSPINLOCK Spinlock, PRTSPINLOCKTMP pTmp);
+/* RTTimeNanoTS - not necessary */
+/* RTTimeMilliTS - not necessary */
+/* RTTimeSystemNanoTS - not necessary */
+/* RTTimeSystemMilliTS - not necessary */
+/* RTThreadNativeSelf - not necessary */
+DECLASM(int) UNWIND_WRAP(RTThreadSleep)(unsigned cMillies);
+DECLASM(bool) UNWIND_WRAP(RTThreadYield)(void);
+#if 0
+/* RTThreadSelf - not necessary */
+DECLASM(int) UNWIND_WRAP(RTThreadCreate)(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
+ RTTHREADTYPE enmType, unsigned fFlags, const char *pszName);
+DECLASM(RTNATIVETHREAD) UNWIND_WRAP(RTThreadGetNative)(RTTHREAD Thread);
+DECLASM(int) UNWIND_WRAP(RTThreadWait)(RTTHREAD Thread, unsigned cMillies, int *prc);
+DECLASM(int) UNWIND_WRAP(RTThreadWaitNoResume)(RTTHREAD Thread, unsigned cMillies, int *prc);
+DECLASM(const char *) UNWIND_WRAP(RTThreadGetName)(RTTHREAD Thread);
+DECLASM(const char *) UNWIND_WRAP(RTThreadSelfName)(void);
+DECLASM(RTTHREADTYPE) UNWIND_WRAP(RTThreadGetType)(RTTHREAD Thread);
+DECLASM(int) UNWIND_WRAP(RTThreadUserSignal)(RTTHREAD Thread);
+DECLASM(int) UNWIND_WRAP(RTThreadUserReset)(RTTHREAD Thread);
+DECLASM(int) UNWIND_WRAP(RTThreadUserWait)(RTTHREAD Thread, unsigned cMillies);
+DECLASM(int) UNWIND_WRAP(RTThreadUserWaitNoResume)(RTTHREAD Thread, unsigned cMillies);
+#endif
+/* RTLogDefaultInstance - a bit of a gamble, but we do not want the overhead! */
+/* RTMpCpuId - not necessary */
+/* RTMpCpuIdFromSetIndex - not necessary */
+/* RTMpCpuIdToSetIndex - not necessary */
+/* RTMpIsCpuPossible - not necessary */
+/* RTMpGetCount - not necessary */
+/* RTMpGetMaxCpuId - not necessary */
+/* RTMpGetOnlineCount - not necessary */
+/* RTMpGetOnlineSet - not necessary */
+/* RTMpGetSet - not necessary */
+/* RTMpIsCpuOnline - not necessary */
+DECLASM(int) UNWIND_WRAP(RTMpOnAll)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+DECLASM(int) UNWIND_WRAP(RTMpOnOthers)(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+DECLASM(int) UNWIND_WRAP(RTMpOnSpecific)(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+DECLASM(int) UNWIND_WRAP(RTMpIsCpuWorkPending)(void);
+/* RTLogRelDefaultInstance - not necessary. */
+DECLASM(int) UNWIND_WRAP(RTLogSetDefaultInstanceThread)(PRTLOGGER pLogger, uintptr_t uKey);
+/* RTLogLogger - can't wrap this buster. */
+/* RTLogLoggerEx - can't wrap this buster. */
+DECLASM(void) UNWIND_WRAP(RTLogLoggerExV)(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
+/* RTLogPrintf - can't wrap this buster. */ /** @todo provide va_list log wrappers in RuntimeR0. */
+DECLASM(void) UNWIND_WRAP(RTLogPrintfV)(const char *pszFormat, va_list args);
+DECLASM(void) UNWIND_WRAP(AssertMsg1)(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction);
+/* AssertMsg2 - can't wrap this buster. */
+#endif /* RT_WITH_W64_UNWIND_HACK */
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Array of the R0 SUP API.
+ */
+static SUPFUNC g_aFunctions[] =
+{
+ /* name function */
+ /* Entries with absolute addresses determined at runtime, fixup
+ code makes ugly ASSUMPTIONS about the order here: */
+ { "SUPR0AbsIs64bit", (void *)0 },
+ { "SUPR0Abs64bitKernelCS", (void *)0 },
+ { "SUPR0Abs64bitKernelSS", (void *)0 },
+ { "SUPR0Abs64bitKernelDS", (void *)0 },
+ { "SUPR0AbsKernelCS", (void *)0 },
+ { "SUPR0AbsKernelSS", (void *)0 },
+ { "SUPR0AbsKernelDS", (void *)0 },
+ { "SUPR0AbsKernelES", (void *)0 },
+ { "SUPR0AbsKernelFS", (void *)0 },
+ { "SUPR0AbsKernelGS", (void *)0 },
+ /* Normal function pointers: */
+ { "SUPR0ComponentRegisterFactory", (void *)UNWIND_WRAP(SUPR0ComponentRegisterFactory) },
+ { "SUPR0ComponentDeregisterFactory", (void *)UNWIND_WRAP(SUPR0ComponentDeregisterFactory) },
+ { "SUPR0ComponentQueryFactory", (void *)UNWIND_WRAP(SUPR0ComponentQueryFactory) },
+ { "SUPR0ObjRegister", (void *)UNWIND_WRAP(SUPR0ObjRegister) },
+ { "SUPR0ObjAddRef", (void *)UNWIND_WRAP(SUPR0ObjAddRef) },
+ { "SUPR0ObjAddRefEx", (void *)UNWIND_WRAP(SUPR0ObjAddRefEx) },
+ { "SUPR0ObjRelease", (void *)UNWIND_WRAP(SUPR0ObjRelease) },
+ { "SUPR0ObjVerifyAccess", (void *)UNWIND_WRAP(SUPR0ObjVerifyAccess) },
+ { "SUPR0LockMem", (void *)UNWIND_WRAP(SUPR0LockMem) },
+ { "SUPR0UnlockMem", (void *)UNWIND_WRAP(SUPR0UnlockMem) },
+ { "SUPR0ContAlloc", (void *)UNWIND_WRAP(SUPR0ContAlloc) },
+ { "SUPR0ContFree", (void *)UNWIND_WRAP(SUPR0ContFree) },
+ { "SUPR0LowAlloc", (void *)UNWIND_WRAP(SUPR0LowAlloc) },
+ { "SUPR0LowFree", (void *)UNWIND_WRAP(SUPR0LowFree) },
+ { "SUPR0MemAlloc", (void *)UNWIND_WRAP(SUPR0MemAlloc) },
+ { "SUPR0MemGetPhys", (void *)UNWIND_WRAP(SUPR0MemGetPhys) },
+ { "SUPR0MemFree", (void *)UNWIND_WRAP(SUPR0MemFree) },
+ { "SUPR0PageAlloc", (void *)UNWIND_WRAP(SUPR0PageAlloc) },
+ { "SUPR0PageFree", (void *)UNWIND_WRAP(SUPR0PageFree) },
+ { "SUPR0Printf", (void *)SUPR0Printf }, /** @todo needs wrapping? */
+ { "SUPR0GetPagingMode", (void *)UNWIND_WRAP(SUPR0GetPagingMode) },
+ { "SUPR0EnableVTx", (void *)SUPR0EnableVTx },
+ { "RTMemAlloc", (void *)UNWIND_WRAP(RTMemAlloc) },
+ { "RTMemAllocZ", (void *)UNWIND_WRAP(RTMemAllocZ) },
+ { "RTMemFree", (void *)UNWIND_WRAP(RTMemFree) },
+ /*{ "RTMemDup", (void *)UNWIND_WRAP(RTMemDup) },
+ { "RTMemDupEx", (void *)UNWIND_WRAP(RTMemDupEx) },*/
+ { "RTMemRealloc", (void *)UNWIND_WRAP(RTMemRealloc) },
+ { "RTR0MemObjAllocLow", (void *)UNWIND_WRAP(RTR0MemObjAllocLow) },
+ { "RTR0MemObjAllocPage", (void *)UNWIND_WRAP(RTR0MemObjAllocPage) },
+ { "RTR0MemObjAllocPhys", (void *)UNWIND_WRAP(RTR0MemObjAllocPhys) },
+ { "RTR0MemObjAllocPhysNC", (void *)UNWIND_WRAP(RTR0MemObjAllocPhysNC) },
+ { "RTR0MemObjAllocCont", (void *)UNWIND_WRAP(RTR0MemObjAllocCont) },
+ { "RTR0MemObjEnterPhys", (void *)UNWIND_WRAP(RTR0MemObjEnterPhys) },
+ { "RTR0MemObjLockUser", (void *)UNWIND_WRAP(RTR0MemObjLockUser) },
+ { "RTR0MemObjMapKernel", (void *)UNWIND_WRAP(RTR0MemObjMapKernel) },
+ { "RTR0MemObjMapKernelEx", (void *)UNWIND_WRAP(RTR0MemObjMapKernelEx) },
+ { "RTR0MemObjMapUser", (void *)UNWIND_WRAP(RTR0MemObjMapUser) },
+ { "RTR0MemObjAddress", (void *)RTR0MemObjAddress },
+ { "RTR0MemObjAddressR3", (void *)RTR0MemObjAddressR3 },
+ { "RTR0MemObjSize", (void *)RTR0MemObjSize },
+ { "RTR0MemObjIsMapping", (void *)RTR0MemObjIsMapping },
+ { "RTR0MemObjGetPagePhysAddr", (void *)RTR0MemObjGetPagePhysAddr },
+ { "RTR0MemObjFree", (void *)UNWIND_WRAP(RTR0MemObjFree) },
+/* These don't work yet on linux - use fast mutexes!
+ { "RTSemMutexCreate", (void *)RTSemMutexCreate },
+ { "RTSemMutexRequest", (void *)RTSemMutexRequest },
+ { "RTSemMutexRelease", (void *)RTSemMutexRelease },
+ { "RTSemMutexDestroy", (void *)RTSemMutexDestroy },
+*/
+ { "RTProcSelf", (void *)RTProcSelf },
+ { "RTR0ProcHandleSelf", (void *)RTR0ProcHandleSelf },
+ { "RTSemFastMutexCreate", (void *)UNWIND_WRAP(RTSemFastMutexCreate) },
+ { "RTSemFastMutexDestroy", (void *)UNWIND_WRAP(RTSemFastMutexDestroy) },
+ { "RTSemFastMutexRequest", (void *)UNWIND_WRAP(RTSemFastMutexRequest) },
+ { "RTSemFastMutexRelease", (void *)UNWIND_WRAP(RTSemFastMutexRelease) },
+ { "RTSemEventCreate", (void *)UNWIND_WRAP(RTSemEventCreate) },
+ { "RTSemEventSignal", (void *)UNWIND_WRAP(RTSemEventSignal) },
+ { "RTSemEventWait", (void *)UNWIND_WRAP(RTSemEventWait) },
+ { "RTSemEventWaitNoResume", (void *)UNWIND_WRAP(RTSemEventWaitNoResume) },
+ { "RTSemEventDestroy", (void *)UNWIND_WRAP(RTSemEventDestroy) },
+ { "RTSemEventMultiCreate", (void *)UNWIND_WRAP(RTSemEventMultiCreate) },
+ { "RTSemEventMultiSignal", (void *)UNWIND_WRAP(RTSemEventMultiSignal) },
+ { "RTSemEventMultiReset", (void *)UNWIND_WRAP(RTSemEventMultiReset) },
+ { "RTSemEventMultiWait", (void *)UNWIND_WRAP(RTSemEventMultiWait) },
+ { "RTSemEventMultiWaitNoResume", (void *)UNWIND_WRAP(RTSemEventMultiWaitNoResume) },
+ { "RTSemEventMultiDestroy", (void *)UNWIND_WRAP(RTSemEventMultiDestroy) },
+ { "RTSpinlockCreate", (void *)UNWIND_WRAP(RTSpinlockCreate) },
+ { "RTSpinlockDestroy", (void *)UNWIND_WRAP(RTSpinlockDestroy) },
+ { "RTSpinlockAcquire", (void *)UNWIND_WRAP(RTSpinlockAcquire) },
+ { "RTSpinlockRelease", (void *)UNWIND_WRAP(RTSpinlockRelease) },
+ { "RTSpinlockAcquireNoInts", (void *)UNWIND_WRAP(RTSpinlockAcquireNoInts) },
+ { "RTSpinlockReleaseNoInts", (void *)UNWIND_WRAP(RTSpinlockReleaseNoInts) },
+ { "RTTimeNanoTS", (void *)RTTimeNanoTS },
+ { "RTTimeMillieTS", (void *)RTTimeMilliTS },
+ { "RTTimeSystemNanoTS", (void *)RTTimeSystemNanoTS },
+ { "RTTimeSystemMillieTS", (void *)RTTimeSystemMilliTS },
+ { "RTThreadNativeSelf", (void *)RTThreadNativeSelf },
+ { "RTThreadSleep", (void *)UNWIND_WRAP(RTThreadSleep) },
+ { "RTThreadYield", (void *)UNWIND_WRAP(RTThreadYield) },
+#if 0 /* Thread APIs, Part 2. */
+ { "RTThreadSelf", (void *)UNWIND_WRAP(RTThreadSelf) },
+ { "RTThreadCreate", (void *)UNWIND_WRAP(RTThreadCreate) }, /** @todo need to wrap the callback */
+ { "RTThreadGetNative", (void *)UNWIND_WRAP(RTThreadGetNative) },
+ { "RTThreadWait", (void *)UNWIND_WRAP(RTThreadWait) },
+ { "RTThreadWaitNoResume", (void *)UNWIND_WRAP(RTThreadWaitNoResume) },
+ { "RTThreadGetName", (void *)UNWIND_WRAP(RTThreadGetName) },
+ { "RTThreadSelfName", (void *)UNWIND_WRAP(RTThreadSelfName) },
+ { "RTThreadGetType", (void *)UNWIND_WRAP(RTThreadGetType) },
+ { "RTThreadUserSignal", (void *)UNWIND_WRAP(RTThreadUserSignal) },
+ { "RTThreadUserReset", (void *)UNWIND_WRAP(RTThreadUserReset) },
+ { "RTThreadUserWait", (void *)UNWIND_WRAP(RTThreadUserWait) },
+ { "RTThreadUserWaitNoResume", (void *)UNWIND_WRAP(RTThreadUserWaitNoResume) },
+#endif
+ { "RTLogDefaultInstance", (void *)RTLogDefaultInstance },
+ { "RTMpCpuId", (void *)RTMpCpuId },
+ { "RTMpCpuIdFromSetIndex", (void *)RTMpCpuIdFromSetIndex },
+ { "RTMpCpuIdToSetIndex", (void *)RTMpCpuIdToSetIndex },
+ { "RTMpIsCpuPossible", (void *)RTMpIsCpuPossible },
+ { "RTMpGetCount", (void *)RTMpGetCount },
+ { "RTMpGetMaxCpuId", (void *)RTMpGetMaxCpuId },
+ { "RTMpGetOnlineCount", (void *)RTMpGetOnlineCount },
+ { "RTMpGetOnlineSet", (void *)RTMpGetOnlineSet },
+ { "RTMpGetSet", (void *)RTMpGetSet },
+ { "RTMpIsCpuOnline", (void *)RTMpIsCpuOnline },
+ { "RTMpIsCpuWorkPending", (void *)UNWIND_WRAP(RTMpIsCpuWorkPending) },
+ { "RTMpOnAll", (void *)UNWIND_WRAP(RTMpOnAll) },
+ { "RTMpOnOthers", (void *)UNWIND_WRAP(RTMpOnOthers) },
+ { "RTMpOnSpecific", (void *)UNWIND_WRAP(RTMpOnSpecific) },
+ { "RTPowerNotificationRegister", (void *)RTPowerNotificationRegister },
+ { "RTPowerNotificationDeregister", (void *)RTPowerNotificationDeregister },
+ { "RTLogRelDefaultInstance", (void *)RTLogRelDefaultInstance },
+ { "RTLogSetDefaultInstanceThread", (void *)UNWIND_WRAP(RTLogSetDefaultInstanceThread) },
+ { "RTLogLogger", (void *)RTLogLogger }, /** @todo remove this */
+ { "RTLogLoggerEx", (void *)RTLogLoggerEx }, /** @todo remove this */
+ { "RTLogLoggerExV", (void *)UNWIND_WRAP(RTLogLoggerExV) },
+ { "RTLogPrintf", (void *)RTLogPrintf }, /** @todo remove this */
+ { "RTLogPrintfV", (void *)UNWIND_WRAP(RTLogPrintfV) },
+ { "AssertMsg1", (void *)UNWIND_WRAP(AssertMsg1) },
+ { "AssertMsg2", (void *)AssertMsg2 }, /** @todo replace this by RTAssertMsg2V */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+ { "RTR0AssertPanicSystem", (void *)RTR0AssertPanicSystem },
+#endif
+#if defined(RT_OS_DARWIN)
+ { "RTAssertMsg1", (void *)RTAssertMsg1 },
+ { "RTAssertMsg2", (void *)RTAssertMsg2 },
+ { "RTAssertMsg2V", (void *)RTAssertMsg2V },
+#endif
+};
+
+#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+/**
+ * Drag in the rest of IRPT since we share it with the
+ * rest of the kernel modules on darwin.
+ */
+PFNRT g_apfnVBoxDrvIPRTDeps[] =
+{
+ (PFNRT)RTCrc32,
+ (PFNRT)RTErrConvertFromErrno,
+ (PFNRT)RTNetIPv4IsHdrValid,
+ (PFNRT)RTNetIPv4TCPChecksum,
+ (PFNRT)RTNetIPv4UDPChecksum,
+ (PFNRT)RTUuidCompare,
+ (PFNRT)RTUuidCompareStr,
+ (PFNRT)RTUuidFromStr,
+ NULL
+};
+#endif /* RT_OS_DARWIN || RT_OS_SOLARIS */
+
+
+/**
+ * Initializes the device extentsion structure.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt The device extension to initialize.
+ */
+int VBOXCALL supdrvInitDevExt(PSUPDRVDEVEXT pDevExt)
+{
+ int rc;
+
+#ifdef SUPDRV_WITH_RELEASE_LOGGER
+ /*
+ * Create the release log.
+ */
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ PRTLOGGER pRelLogger;
+ rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
+ "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
+ RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
+ if (RT_SUCCESS(rc))
+ RTLogRelSetDefaultInstance(pRelLogger);
+#endif
+
+ /*
+ * Initialize it.
+ */
+ memset(pDevExt, 0, sizeof(*pDevExt));
+ rc = RTSpinlockCreate(&pDevExt->Spinlock);
+ if (!rc)
+ {
+ rc = RTSemFastMutexCreate(&pDevExt->mtxLdr);
+ if (!rc)
+ {
+ rc = RTSemFastMutexCreate(&pDevExt->mtxComponentFactory);
+ if (!rc)
+ {
+ rc = RTSemFastMutexCreate(&pDevExt->mtxGip);
+ if (!rc)
+ {
+ rc = supdrvGipCreate(pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ pDevExt->u32Cookie = BIRD; /** @todo make this random? */
+
+ /*
+ * Fixup the absolute symbols.
+ *
+ * Because of the table indexing assumptions we'll do #ifdef orgy here rather
+ * than distributing this to OS specific files. At least for now.
+ */
+#ifdef RT_OS_DARWIN
+ if (SUPR0GetPagingMode() >= SUPPAGINGMODE_AMD64)
+ {
+ g_aFunctions[0].pfn = (void *)1; /* SUPR0AbsIs64bit */
+ g_aFunctions[1].pfn = (void *)0x80; /* SUPR0Abs64bitKernelCS - KERNEL64_CS, seg.h */
+ g_aFunctions[2].pfn = (void *)0x88; /* SUPR0Abs64bitKernelSS - KERNEL64_SS, seg.h */
+ g_aFunctions[3].pfn = (void *)0x88; /* SUPR0Abs64bitKernelDS - KERNEL64_SS, seg.h */
+ }
+ else
+ g_aFunctions[0].pfn = g_aFunctions[1].pfn = g_aFunctions[2].pfn = g_aFunctions[4].pfn = (void *)0;
+ g_aFunctions[4].pfn = (void *)0x08; /* SUPR0AbsKernelCS - KERNEL_CS, seg.h */
+ g_aFunctions[5].pfn = (void *)0x10; /* SUPR0AbsKernelSS - KERNEL_DS, seg.h */
+ g_aFunctions[6].pfn = (void *)0x10; /* SUPR0AbsKernelDS - KERNEL_DS, seg.h */
+ g_aFunctions[7].pfn = (void *)0x10; /* SUPR0AbsKernelES - KERNEL_DS, seg.h */
+#else
+# if ARCH_BITS == 64
+ g_aFunctions[0].pfn = (void *)1; /* SUPR0AbsIs64bit */
+ g_aFunctions[1].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0Abs64bitKernelCS */
+ g_aFunctions[2].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0Abs64bitKernelSS */
+ g_aFunctions[3].pfn = (void *)(uintptr_t)ASMGetDS(); /* SUPR0Abs64bitKernelDS */
+# elif ARCH_BITS == 32
+ g_aFunctions[0].pfn = g_aFunctions[1].pfn = g_aFunctions[2].pfn = g_aFunctions[4].pfn = (void *)0;
+# endif
+ g_aFunctions[4].pfn = (void *)(uintptr_t)ASMGetCS(); /* SUPR0AbsKernelCS */
+ g_aFunctions[5].pfn = (void *)(uintptr_t)ASMGetSS(); /* SUPR0AbsKernelSS */
+ g_aFunctions[6].pfn = (void *)(uintptr_t)ASMGetDS(); /* SUPR0AbsKernelDS */
+ g_aFunctions[7].pfn = (void *)(uintptr_t)ASMGetES(); /* SUPR0AbsKernelES */
+#endif
+ g_aFunctions[8].pfn = (void *)(uintptr_t)ASMGetFS(); /* SUPR0AbsKernelFS */
+ g_aFunctions[9].pfn = (void *)(uintptr_t)ASMGetGS(); /* SUPR0AbsKernelGS */
+ return VINF_SUCCESS;
+ }
+
+ RTSemFastMutexDestroy(pDevExt->mtxGip);
+ pDevExt->mtxGip = NIL_RTSEMFASTMUTEX;
+ }
+ RTSemFastMutexDestroy(pDevExt->mtxComponentFactory);
+ pDevExt->mtxComponentFactory = NIL_RTSEMFASTMUTEX;
+ }
+ RTSemFastMutexDestroy(pDevExt->mtxLdr);
+ pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
+ }
+ RTSpinlockDestroy(pDevExt->Spinlock);
+ pDevExt->Spinlock = NIL_RTSPINLOCK;
+ }
+#ifdef SUPDRV_WITH_RELEASE_LOGGER
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+
+ return rc;
+}
+
+
+/**
+ * Delete the device extension (e.g. cleanup members).
+ *
+ * @param pDevExt The device extension to delete.
+ */
+void VBOXCALL supdrvDeleteDevExt(PSUPDRVDEVEXT pDevExt)
+{
+ PSUPDRVOBJ pObj;
+ PSUPDRVUSAGE pUsage;
+
+ /*
+ * Kill mutexes and spinlocks.
+ */
+ RTSemFastMutexDestroy(pDevExt->mtxGip);
+ pDevExt->mtxGip = NIL_RTSEMFASTMUTEX;
+ RTSemFastMutexDestroy(pDevExt->mtxLdr);
+ pDevExt->mtxLdr = NIL_RTSEMFASTMUTEX;
+ RTSpinlockDestroy(pDevExt->Spinlock);
+ pDevExt->Spinlock = NIL_RTSPINLOCK;
+ RTSemFastMutexDestroy(pDevExt->mtxComponentFactory);
+ pDevExt->mtxComponentFactory = NIL_RTSEMFASTMUTEX;
+
+ /*
+ * Free lists.
+ */
+ /* objects. */
+ pObj = pDevExt->pObjs;
+#if !defined(DEBUG_bird) || !defined(RT_OS_LINUX) /* breaks unloading, temporary, remove me! */
+ Assert(!pObj); /* (can trigger on forced unloads) */
+#endif
+ pDevExt->pObjs = NULL;
+ while (pObj)
+ {
+ void *pvFree = pObj;
+ pObj = pObj->pNext;
+ RTMemFree(pvFree);
+ }
+
+ /* usage records. */
+ pUsage = pDevExt->pUsageFree;
+ pDevExt->pUsageFree = NULL;
+ while (pUsage)
+ {
+ void *pvFree = pUsage;
+ pUsage = pUsage->pNext;
+ RTMemFree(pvFree);
+ }
+
+ /* kill the GIP. */
+ supdrvGipDestroy(pDevExt);
+
+#ifdef SUPDRV_WITH_RELEASE_LOGGER
+ /* destroy the loggers. */
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+#endif
+}
+
+
+/**
+ * Create session.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Device extension.
+ * @param fUser Flag indicating whether this is a user or kernel session.
+ * @param ppSession Where to store the pointer to the session data.
+ */
+int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSION *ppSession)
+{
+ /*
+ * Allocate memory for the session data.
+ */
+ int rc = VERR_NO_MEMORY;
+ PSUPDRVSESSION pSession = *ppSession = (PSUPDRVSESSION)RTMemAllocZ(sizeof(*pSession));
+ if (pSession)
+ {
+ /* Initialize session data. */
+ rc = RTSpinlockCreate(&pSession->Spinlock);
+ if (!rc)
+ {
+ Assert(pSession->Spinlock != NIL_RTSPINLOCK);
+ pSession->pDevExt = pDevExt;
+ pSession->u32Cookie = BIRD_INV;
+ /*pSession->pLdrUsage = NULL;
+ pSession->pVM = NULL;
+ pSession->pUsage = NULL;
+ pSession->pGip = NULL;
+ pSession->fGipReferenced = false;
+ pSession->Bundle.cUsed = 0; */
+ pSession->Uid = NIL_RTUID;
+ pSession->Gid = NIL_RTGID;
+ if (fUser)
+ {
+ pSession->Process = RTProcSelf();
+ pSession->R0Process = RTR0ProcHandleSelf();
+ }
+ else
+ {
+ pSession->Process = NIL_RTPROCESS;
+ pSession->R0Process = NIL_RTR0PROCESS;
+ }
+
+ LogFlow(("Created session %p initial cookie=%#x\n", pSession, pSession->u32Cookie));
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(pSession);
+ *ppSession = NULL;
+ Log(("Failed to create spinlock, rc=%d!\n", rc));
+ }
+
+ return rc;
+}
+
+
+/**
+ * Shared code for cleaning up a session.
+ *
+ * @param pDevExt Device extension.
+ * @param pSession Session data.
+ * This data will be freed by this routine.
+ */
+void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
+{
+ /*
+ * Cleanup the session first.
+ */
+ supdrvCleanupSession(pDevExt, pSession);
+
+ /*
+ * Free the rest of the session stuff.
+ */
+ RTSpinlockDestroy(pSession->Spinlock);
+ pSession->Spinlock = NIL_RTSPINLOCK;
+ pSession->pDevExt = NULL;
+ RTMemFree(pSession);
+ LogFlow(("supdrvCloseSession: returns\n"));
+}
+
+
+/**
+ * Shared code for cleaning up a session (but not quite freeing it).
+ *
+ * This is primarily intended for MAC OS X where we have to clean up the memory
+ * stuff before the file handle is closed.
+ *
+ * @param pDevExt Device extension.
+ * @param pSession Session data.
+ * This data will be freed by this routine.
+ */
+void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
+{
+ PSUPDRVBUNDLE pBundle;
+ LogFlow(("supdrvCleanupSession: pSession=%p\n", pSession));
+
+ /*
+ * Remove logger instances related to this session.
+ */
+ RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pSession);
+
+ /*
+ * Release object references made in this session.
+ * In theory there should be noone racing us in this session.
+ */
+ Log2(("release objects - start\n"));
+ if (pSession->pUsage)
+ {
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ PSUPDRVUSAGE pUsage;
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+
+ while ((pUsage = pSession->pUsage) != NULL)
+ {
+ PSUPDRVOBJ pObj = pUsage->pObj;
+ pSession->pUsage = pUsage->pNext;
+
+ AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
+ if (pUsage->cUsage < pObj->cUsage)
+ {
+ pObj->cUsage -= pUsage->cUsage;
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ }
+ else
+ {
+ /* Destroy the object and free the record. */
+ if (pDevExt->pObjs == pObj)
+ pDevExt->pObjs = pObj->pNext;
+ else
+ {
+ PSUPDRVOBJ pObjPrev;
+ for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
+ if (pObjPrev->pNext == pObj)
+ {
+ pObjPrev->pNext = pObj->pNext;
+ break;
+ }
+ Assert(pObjPrev);
+ }
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ Log(("supdrvCleanupSession: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
+ pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
+ if (pObj->pfnDestructor)
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapObjDestructor((PFNRT)pObj->pfnDestructor, pObj, pObj->pvUser1, pObj->pvUser2);
+#else
+ pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
+#endif
+ RTMemFree(pObj);
+ }
+
+ /* free it and continue. */
+ RTMemFree(pUsage);
+
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+ }
+
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ AssertMsg(!pSession->pUsage, ("Some buster reregistered an object during desturction!\n"));
+ }
+ Log2(("release objects - done\n"));
+
+ /*
+ * Release memory allocated in the session.
+ *
+ * We do not serialize this as we assume that the application will
+ * not allocated memory while closing the file handle object.
+ */
+ Log2(("freeing memory:\n"));
+ pBundle = &pSession->Bundle;
+ while (pBundle)
+ {
+ PSUPDRVBUNDLE pToFree;
+ unsigned i;
+
+ /*
+ * Check and unlock all entries in the bundle.
+ */
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if (pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ)
+ {
+ int rc;
+ Log2(("eType=%d pvR0=%p pvR3=%p cb=%ld\n", pBundle->aMem[i].eType, RTR0MemObjAddress(pBundle->aMem[i].MemObj),
+ (void *)RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3), (long)RTR0MemObjSize(pBundle->aMem[i].MemObj)));
+ if (pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ)
+ {
+ rc = RTR0MemObjFree(pBundle->aMem[i].MapObjR3, false);
+ AssertRC(rc); /** @todo figure out how to handle this. */
+ pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
+ }
+ rc = RTR0MemObjFree(pBundle->aMem[i].MemObj, true /* fFreeMappings */);
+ AssertRC(rc); /** @todo figure out how to handle this. */
+ pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
+ pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
+ }
+ }
+
+ /*
+ * Advance and free previous bundle.
+ */
+ pToFree = pBundle;
+ pBundle = pBundle->pNext;
+
+ pToFree->pNext = NULL;
+ pToFree->cUsed = 0;
+ if (pToFree != &pSession->Bundle)
+ RTMemFree(pToFree);
+ }
+ Log2(("freeing memory - done\n"));
+
+ /*
+ * Deregister component factories.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxComponentFactory);
+ Log2(("deregistering component factories:\n"));
+ if (pDevExt->pComponentFactoryHead)
+ {
+ PSUPDRVFACTORYREG pPrev = NULL;
+ PSUPDRVFACTORYREG pCur = pDevExt->pComponentFactoryHead;
+ while (pCur)
+ {
+ if (pCur->pSession == pSession)
+ {
+ /* unlink it */
+ PSUPDRVFACTORYREG pNext = pCur->pNext;
+ if (pPrev)
+ pPrev->pNext = pNext;
+ else
+ pDevExt->pComponentFactoryHead = pNext;
+
+ /* free it */
+ pCur->pNext = NULL;
+ pCur->pSession = NULL;
+ pCur->pFactory = NULL;
+ RTMemFree(pCur);
+
+ /* next */
+ pCur = pNext;
+ }
+ else
+ {
+ /* next */
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+ }
+ }
+ RTSemFastMutexRelease(pDevExt->mtxComponentFactory);
+ Log2(("deregistering component factories - done\n"));
+
+ /*
+ * Loaded images needs to be dereferenced and possibly freed up.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+ Log2(("freeing images:\n"));
+ if (pSession->pLdrUsage)
+ {
+ PSUPDRVLDRUSAGE pUsage = pSession->pLdrUsage;
+ pSession->pLdrUsage = NULL;
+ while (pUsage)
+ {
+ void *pvFree = pUsage;
+ PSUPDRVLDRIMAGE pImage = pUsage->pImage;
+ if (pImage->cUsage > pUsage->cUsage)
+ pImage->cUsage -= pUsage->cUsage;
+ else
+ supdrvLdrFree(pDevExt, pImage);
+ pUsage->pImage = NULL;
+ pUsage = pUsage->pNext;
+ RTMemFree(pvFree);
+ }
+ }
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log2(("freeing images - done\n"));
+
+ /*
+ * Unmap the GIP.
+ */
+ Log2(("umapping GIP:\n"));
+ if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
+ {
+ SUPR0GipUnmap(pSession);
+ pSession->fGipReferenced = 0;
+ }
+ Log2(("umapping GIP - done\n"));
+}
+
+
+/**
+ * Fast path I/O Control worker.
+ *
+ * @returns VBox status code that should be passed down to ring-3 unchanged.
+ * @param uIOCtl Function number.
+ * @param idCpu VMCPU id.
+ * @param pDevExt Device extention.
+ * @param pSession Session data.
+ */
+int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, unsigned idCpu, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
+{
+ /*
+ * We check the two prereqs after doing this only to allow the compiler to optimize things better.
+ */
+ if (RT_LIKELY(pSession->pVM && pDevExt->pfnVMMR0EntryFast))
+ {
+ switch (uIOCtl)
+ {
+ case SUP_IOCTL_FAST_DO_RAW_RUN:
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
+#else
+ pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
+#endif
+ break;
+ case SUP_IOCTL_FAST_DO_HWACC_RUN:
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_HWACC_RUN);
+#else
+ pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_HWACC_RUN);
+#endif
+ break;
+ case SUP_IOCTL_FAST_DO_NOP:
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapVMMR0EntryFast((PFNRT)pDevExt->pfnVMMR0EntryFast, pSession->pVM, idCpu, SUP_VMMR0_DO_NOP);
+#else
+ pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_NOP);
+#endif
+ break;
+ default:
+ return VERR_INTERNAL_ERROR;
+ }
+ return VINF_SUCCESS;
+ }
+ return VERR_INTERNAL_ERROR;
+}
+
+
+/**
+ * Helper for supdrvIOCtl. Check if pszStr contains any character of pszChars.
+ * We would use strpbrk here if this function would be contained in the RedHat kABI white
+ * list, see http://www.kerneldrivers.org/RHEL5.
+ *
+ * @return 1 if pszStr does contain any character of pszChars, 0 otherwise.
+ * @param pszStr String to check
+ * @param pszChars Character set
+ */
+static int supdrvCheckInvalidChar(const char *pszStr, const char *pszChars)
+{
+ int chCur;
+ while ((chCur = *pszStr++) != '\0')
+ {
+ int ch;
+ const char *psz = pszChars;
+ while ((ch = *psz++) != '\0')
+ if (ch == chCur)
+ return 1;
+
+ }
+ return 0;
+}
+
+
+/**
+ * I/O Control worker.
+ *
+ * @returns 0 on success.
+ * @returns VERR_INVALID_PARAMETER if the request is invalid.
+ *
+ * @param uIOCtl Function number.
+ * @param pDevExt Device extention.
+ * @param pSession Session data.
+ * @param pReqHdr The request header.
+ */
+int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr)
+{
+ /*
+ * Validate the request.
+ */
+ /* this first check could probably be omitted as its also done by the OS specific code... */
+ if (RT_UNLIKELY( (pReqHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC
+ || pReqHdr->cbIn < sizeof(*pReqHdr)
+ || pReqHdr->cbOut < sizeof(*pReqHdr)))
+ {
+ OSDBGPRINT(("vboxdrv: Bad ioctl request header; cbIn=%#lx cbOut=%#lx fFlags=%#lx\n",
+ (long)pReqHdr->cbIn, (long)pReqHdr->cbOut, (long)pReqHdr->fFlags));
+ return VERR_INVALID_PARAMETER;
+ }
+ if (RT_UNLIKELY(uIOCtl == SUP_IOCTL_COOKIE))
+ {
+ if (pReqHdr->u32Cookie != SUPCOOKIE_INITIAL_COOKIE)
+ {
+ OSDBGPRINT(("SUP_IOCTL_COOKIE: bad cookie %#lx\n", (long)pReqHdr->u32Cookie));
+ return VERR_INVALID_PARAMETER;
+ }
+ }
+ else if (RT_UNLIKELY( pReqHdr->u32Cookie != pDevExt->u32Cookie
+ || pReqHdr->u32SessionCookie != pSession->u32Cookie))
+ {
+ OSDBGPRINT(("vboxdrv: bad cookie %#lx / %#lx.\n", (long)pReqHdr->u32Cookie, (long)pReqHdr->u32SessionCookie));
+ return VERR_INVALID_PARAMETER;
+ }
+
+/*
+ * Validation macros
+ */
+#define REQ_CHECK_SIZES_EX(Name, cbInExpect, cbOutExpect) \
+ do { \
+ if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect) || pReqHdr->cbOut != (cbOutExpect))) \
+ { \
+ OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld. cbOut=%ld expected %ld.\n", \
+ (long)pReq->Hdr.cbIn, (long)(cbInExpect), (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
+ return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+#define REQ_CHECK_SIZES(Name) REQ_CHECK_SIZES_EX(Name, Name ## _SIZE_IN, Name ## _SIZE_OUT)
+
+#define REQ_CHECK_SIZE_IN(Name, cbInExpect) \
+ do { \
+ if (RT_UNLIKELY(pReqHdr->cbIn != (cbInExpect))) \
+ { \
+ OSDBGPRINT(( #Name ": Invalid input/output sizes. cbIn=%ld expected %ld.\n", \
+ (long)pReq->Hdr.cbIn, (long)(cbInExpect))); \
+ return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+#define REQ_CHECK_SIZE_OUT(Name, cbOutExpect) \
+ do { \
+ if (RT_UNLIKELY(pReqHdr->cbOut != (cbOutExpect))) \
+ { \
+ OSDBGPRINT(( #Name ": Invalid input/output sizes. cbOut=%ld expected %ld.\n", \
+ (long)pReq->Hdr.cbOut, (long)(cbOutExpect))); \
+ return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+#define REQ_CHECK_EXPR(Name, expr) \
+ do { \
+ if (RT_UNLIKELY(!(expr))) \
+ { \
+ OSDBGPRINT(( #Name ": %s\n", #expr)); \
+ return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+#define REQ_CHECK_EXPR_FMT(expr, fmt) \
+ do { \
+ if (RT_UNLIKELY(!(expr))) \
+ { \
+ OSDBGPRINT( fmt ); \
+ return pReq->Hdr.rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+
+ /*
+ * The switch.
+ */
+ switch (SUP_CTL_CODE_NO_SIZE(uIOCtl))
+ {
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_COOKIE):
+ {
+ PSUPCOOKIE pReq = (PSUPCOOKIE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_COOKIE);
+ if (strncmp(pReq->u.In.szMagic, SUPCOOKIE_MAGIC, sizeof(pReq->u.In.szMagic)))
+ {
+ OSDBGPRINT(("SUP_IOCTL_COOKIE: invalid magic %.16s\n", pReq->u.In.szMagic));
+ pReq->Hdr.rc = VERR_INVALID_MAGIC;
+ return 0;
+ }
+
+#if 0
+ /*
+ * Call out to the OS specific code and let it do permission checks on the
+ * client process.
+ */
+ if (!supdrvOSValidateClientProcess(pDevExt, pSession))
+ {
+ pReq->u.Out.u32Cookie = 0xffffffff;
+ pReq->u.Out.u32SessionCookie = 0xffffffff;
+ pReq->u.Out.u32SessionVersion = 0xffffffff;
+ pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
+ pReq->u.Out.pSession = NULL;
+ pReq->u.Out.cFunctions = 0;
+ pReq->Hdr.rc = VERR_PERMISSION_DENIED;
+ return 0;
+ }
+#endif
+
+ /*
+ * Match the version.
+ * The current logic is very simple, match the major interface version.
+ */
+ if ( pReq->u.In.u32MinVersion > SUPDRV_IOC_VERSION
+ || (pReq->u.In.u32MinVersion & 0xffff0000) != (SUPDRV_IOC_VERSION & 0xffff0000))
+ {
+ OSDBGPRINT(("SUP_IOCTL_COOKIE: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
+ pReq->u.In.u32ReqVersion, pReq->u.In.u32MinVersion, SUPDRV_IOC_VERSION));
+ pReq->u.Out.u32Cookie = 0xffffffff;
+ pReq->u.Out.u32SessionCookie = 0xffffffff;
+ pReq->u.Out.u32SessionVersion = 0xffffffff;
+ pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
+ pReq->u.Out.pSession = NULL;
+ pReq->u.Out.cFunctions = 0;
+ pReq->Hdr.rc = VERR_VERSION_MISMATCH;
+ return 0;
+ }
+
+ /*
+ * Fill in return data and be gone.
+ * N.B. The first one to change SUPDRV_IOC_VERSION shall makes sure that
+ * u32SessionVersion <= u32ReqVersion!
+ */
+ /** @todo Somehow validate the client and negotiate a secure cookie... */
+ pReq->u.Out.u32Cookie = pDevExt->u32Cookie;
+ pReq->u.Out.u32SessionCookie = pSession->u32Cookie;
+ pReq->u.Out.u32SessionVersion = SUPDRV_IOC_VERSION;
+ pReq->u.Out.u32DriverVersion = SUPDRV_IOC_VERSION;
+ pReq->u.Out.pSession = pSession;
+ pReq->u.Out.cFunctions = sizeof(g_aFunctions) / sizeof(g_aFunctions[0]);
+ pReq->Hdr.rc = VINF_SUCCESS;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_QUERY_FUNCS(0)):
+ {
+ /* validate */
+ PSUPQUERYFUNCS pReq = (PSUPQUERYFUNCS)pReqHdr;
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_QUERY_FUNCS, SUP_IOCTL_QUERY_FUNCS_SIZE_IN, SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(RT_ELEMENTS(g_aFunctions)));
+
+ /* execute */
+ pReq->u.Out.cFunctions = RT_ELEMENTS(g_aFunctions);
+ memcpy(&pReq->u.Out.aFunctions[0], g_aFunctions, sizeof(g_aFunctions));
+ pReq->Hdr.rc = VINF_SUCCESS;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_IDT_INSTALL):
+ {
+ /* validate */
+ PSUPIDTINSTALL pReq = (PSUPIDTINSTALL)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_IDT_INSTALL);
+
+ /* execute */
+ pReq->u.Out.u8Idt = 3;
+ pReq->Hdr.rc = VERR_NOT_SUPPORTED;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_IDT_REMOVE):
+ {
+ /* validate */
+ PSUPIDTREMOVE pReq = (PSUPIDTREMOVE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_IDT_REMOVE);
+
+ /* execute */
+ pReq->Hdr.rc = VERR_NOT_SUPPORTED;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_LOCK):
+ {
+ /* validate */
+ PSUPPAGELOCK pReq = (PSUPPAGELOCK)pReqHdr;
+ REQ_CHECK_SIZE_IN(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_IN);
+ REQ_CHECK_SIZE_OUT(SUP_IOCTL_PAGE_LOCK, SUP_IOCTL_PAGE_LOCK_SIZE_OUT(pReq->u.In.cPages));
+ REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.cPages > 0);
+ REQ_CHECK_EXPR(SUP_IOCTL_PAGE_LOCK, pReq->u.In.pvR3 >= PAGE_SIZE);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0LockMem(pSession, pReq->u.In.pvR3, pReq->u.In.cPages, &pReq->u.Out.aPages[0]);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_UNLOCK):
+ {
+ /* validate */
+ PSUPPAGEUNLOCK pReq = (PSUPPAGEUNLOCK)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_PAGE_UNLOCK);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0UnlockMem(pSession, pReq->u.In.pvR3);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_ALLOC):
+ {
+ /* validate */
+ PSUPCONTALLOC pReq = (PSUPCONTALLOC)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_CONT_ALLOC);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0ContAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.HCPhys);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CONT_FREE):
+ {
+ /* validate */
+ PSUPCONTFREE pReq = (PSUPCONTFREE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_CONT_FREE);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0ContFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_OPEN):
+ {
+ /* validate */
+ PSUPLDROPEN pReq = (PSUPLDROPEN)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_LDR_OPEN);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImage > 0);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.cbImage < _1M*16);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, pReq->u.In.szName[0]);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, memchr(pReq->u.In.szName, '\0', sizeof(pReq->u.In.szName)));
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_OPEN, !supdrvCheckInvalidChar(pReq->u.In.szName, ";:()[]{}/\\|&*%#@!~`\"'"));
+
+ /* execute */
+ pReq->Hdr.rc = supdrvIOCtl_LdrOpen(pDevExt, pSession, pReq);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_LOAD):
+ {
+ /* validate */
+ PSUPLDRLOAD pReq = (PSUPLDRLOAD)pReqHdr;
+ REQ_CHECK_EXPR(Name, pReq->Hdr.cbIn >= sizeof(*pReq));
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_LDR_LOAD, SUP_IOCTL_LDR_LOAD_SIZE_IN(pReq->u.In.cbImage), SUP_IOCTL_LDR_LOAD_SIZE_OUT);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_LOAD, pReq->u.In.cSymbols <= 16384);
+ REQ_CHECK_EXPR_FMT( !pReq->u.In.cSymbols
+ || ( pReq->u.In.offSymbols < pReq->u.In.cbImage
+ && pReq->u.In.offSymbols + pReq->u.In.cSymbols * sizeof(SUPLDRSYM) <= pReq->u.In.cbImage),
+ ("SUP_IOCTL_LDR_LOAD: offSymbols=%#lx cSymbols=%#lx cbImage=%#lx\n", (long)pReq->u.In.offSymbols,
+ (long)pReq->u.In.cSymbols, (long)pReq->u.In.cbImage));
+ REQ_CHECK_EXPR_FMT( !pReq->u.In.cbStrTab
+ || ( pReq->u.In.offStrTab < pReq->u.In.cbImage
+ && pReq->u.In.offStrTab + pReq->u.In.cbStrTab <= pReq->u.In.cbImage
+ && pReq->u.In.cbStrTab <= pReq->u.In.cbImage),
+ ("SUP_IOCTL_LDR_LOAD: offStrTab=%#lx cbStrTab=%#lx cbImage=%#lx\n", (long)pReq->u.In.offStrTab,
+ (long)pReq->u.In.cbStrTab, (long)pReq->u.In.cbImage));
+
+ if (pReq->u.In.cSymbols)
+ {
+ uint32_t i;
+ PSUPLDRSYM paSyms = (PSUPLDRSYM)&pReq->u.In.achImage[pReq->u.In.offSymbols];
+ for (i = 0; i < pReq->u.In.cSymbols; i++)
+ {
+ REQ_CHECK_EXPR_FMT(paSyms[i].offSymbol < pReq->u.In.cbImage,
+ ("SUP_IOCTL_LDR_LOAD: sym #%ld: symb off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offSymbol, (long)pReq->u.In.cbImage));
+ REQ_CHECK_EXPR_FMT(paSyms[i].offName < pReq->u.In.cbStrTab,
+ ("SUP_IOCTL_LDR_LOAD: sym #%ld: name off %#lx (max=%#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
+ REQ_CHECK_EXPR_FMT(memchr(&pReq->u.In.achImage[pReq->u.In.offStrTab + paSyms[i].offName], '\0', pReq->u.In.cbStrTab - paSyms[i].offName),
+ ("SUP_IOCTL_LDR_LOAD: sym #%ld: unterminated name! (%#lx / %#lx)\n", (long)i, (long)paSyms[i].offName, (long)pReq->u.In.cbImage));
+ }
+ }
+
+ /* execute */
+ pReq->Hdr.rc = supdrvIOCtl_LdrLoad(pDevExt, pSession, pReq);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_FREE):
+ {
+ /* validate */
+ PSUPLDRFREE pReq = (PSUPLDRFREE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_LDR_FREE);
+
+ /* execute */
+ pReq->Hdr.rc = supdrvIOCtl_LdrFree(pDevExt, pSession, pReq);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LDR_GET_SYMBOL):
+ {
+ /* validate */
+ PSUPLDRGETSYMBOL pReq = (PSUPLDRGETSYMBOL)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_LDR_GET_SYMBOL);
+ REQ_CHECK_EXPR(SUP_IOCTL_LDR_GET_SYMBOL, memchr(pReq->u.In.szSymbol, '\0', sizeof(pReq->u.In.szSymbol)));
+
+ /* execute */
+ pReq->Hdr.rc = supdrvIOCtl_LdrGetSymbol(pDevExt, pSession, pReq);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CALL_VMMR0(0)):
+ {
+ /* validate */
+ PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)pReqHdr;
+ Log4(("SUP_IOCTL_CALL_VMMR0: op=%u in=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ pReq->u.In.uOperation, pReq->Hdr.cbIn, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+
+ if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_VMMR0_SIZE(0))
+ {
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(0), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0));
+
+ /* execute */
+ if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
+#ifdef RT_WITH_W64_UNWIND_HACK
+ pReq->Hdr.rc = supdrvNtWrapVMMR0EntryEx((PFNRT)pDevExt->pfnVMMR0EntryEx, pReq->u.In.pVMR0, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
+#else
+ pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
+#endif
+ else
+ pReq->Hdr.rc = VERR_WRONG_ORDER;
+ }
+ else
+ {
+ PSUPVMMR0REQHDR pVMMReq = (PSUPVMMR0REQHDR)&pReq->abReqPkt[0];
+ REQ_CHECK_EXPR_FMT(pReq->Hdr.cbIn >= SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR)),
+ ("SUP_IOCTL_CALL_VMMR0: cbIn=%#x < %#lx\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_VMMR0_SIZE(sizeof(SUPVMMR0REQHDR))));
+ REQ_CHECK_EXPR(SUP_IOCTL_CALL_VMMR0, pVMMReq->u32Magic == SUPVMMR0REQHDR_MAGIC);
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_VMMR0, SUP_IOCTL_CALL_VMMR0_SIZE_IN(pVMMReq->cbReq), SUP_IOCTL_CALL_VMMR0_SIZE_OUT(pVMMReq->cbReq));
+
+ /* execute */
+ if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
+#ifdef RT_WITH_W64_UNWIND_HACK
+ pReq->Hdr.rc = supdrvNtWrapVMMR0EntryEx((PFNRT)pDevExt->pfnVMMR0EntryEx, pReq->u.In.pVMR0, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+#else
+ pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+#endif
+ else
+ pReq->Hdr.rc = VERR_WRONG_ORDER;
+ }
+
+ if ( RT_FAILURE(pReq->Hdr.rc)
+ && pReq->Hdr.rc != VERR_INTERRUPTED
+ && pReq->Hdr.rc != VERR_TIMEOUT)
+ Log(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+ else
+ Log4(("SUP_IOCTL_CALL_VMMR0: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ pReq->Hdr.rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GET_PAGING_MODE):
+ {
+ /* validate */
+ PSUPGETPAGINGMODE pReq = (PSUPGETPAGINGMODE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_GET_PAGING_MODE);
+
+ /* execute */
+ pReq->Hdr.rc = VINF_SUCCESS;
+ pReq->u.Out.enmMode = SUPR0GetPagingMode();
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_ALLOC):
+ {
+ /* validate */
+ PSUPLOWALLOC pReq = (PSUPLOWALLOC)pReqHdr;
+ REQ_CHECK_EXPR(SUP_IOCTL_LOW_ALLOC, pReq->Hdr.cbIn <= SUP_IOCTL_LOW_ALLOC_SIZE_IN);
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_LOW_ALLOC, SUP_IOCTL_LOW_ALLOC_SIZE_IN, SUP_IOCTL_LOW_ALLOC_SIZE_OUT(pReq->u.In.cPages));
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0LowAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR0, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_LOW_FREE):
+ {
+ /* validate */
+ PSUPLOWFREE pReq = (PSUPLOWFREE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_LOW_FREE);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0LowFree(pSession, (RTHCUINTPTR)pReq->u.In.pvR3);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_MAP):
+ {
+ /* validate */
+ PSUPGIPMAP pReq = (PSUPGIPMAP)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_GIP_MAP);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0GipMap(pSession, &pReq->u.Out.pGipR3, &pReq->u.Out.HCPhysGip);
+ if (RT_SUCCESS(pReq->Hdr.rc))
+ pReq->u.Out.pGipR0 = pDevExt->pGip;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_GIP_UNMAP):
+ {
+ /* validate */
+ PSUPGIPUNMAP pReq = (PSUPGIPUNMAP)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_GIP_UNMAP);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0GipUnmap(pSession);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_SET_VM_FOR_FAST):
+ {
+ /* validate */
+ PSUPSETVMFORFAST pReq = (PSUPSETVMFORFAST)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_SET_VM_FOR_FAST);
+ REQ_CHECK_EXPR_FMT( !pReq->u.In.pVMR0
+ || ( VALID_PTR(pReq->u.In.pVMR0)
+ && !((uintptr_t)pReq->u.In.pVMR0 & (PAGE_SIZE - 1))),
+ ("SUP_IOCTL_SET_VM_FOR_FAST: pVMR0=%p!\n", pReq->u.In.pVMR0));
+ /* execute */
+ pSession->pVM = pReq->u.In.pVMR0;
+ pReq->Hdr.rc = VINF_SUCCESS;
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_ALLOC):
+ {
+ /* validate */
+ PSUPPAGEALLOC pReq = (PSUPPAGEALLOC)pReqHdr;
+ REQ_CHECK_EXPR(SUP_IOCTL_PAGE_ALLOC, pReq->Hdr.cbIn <= SUP_IOCTL_PAGE_ALLOC_SIZE_IN);
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_PAGE_ALLOC, SUP_IOCTL_PAGE_ALLOC_SIZE_IN, SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(pReq->u.In.cPages));
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0PageAlloc(pSession, pReq->u.In.cPages, &pReq->u.Out.pvR3, &pReq->u.Out.aPages[0]);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_ALLOC_EX):
+ {
+ /* validate */
+ PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)pReqHdr;
+ REQ_CHECK_EXPR(SUP_IOCTL_PAGE_ALLOC_EX, pReq->Hdr.cbIn <= SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN);
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_PAGE_ALLOC_EX, SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN, SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(pReq->u.In.cPages));
+ REQ_CHECK_EXPR_FMT(pReq->u.In.fKernelMapping || pReq->u.In.fUserMapping,
+ ("SUP_IOCTL_PAGE_ALLOC_EX: No mapping requested!\n"));
+ REQ_CHECK_EXPR_FMT(pReq->u.In.fUserMapping,
+ ("SUP_IOCTL_PAGE_ALLOC_EX: Must have user mapping!\n"));
+ REQ_CHECK_EXPR_FMT(!pReq->u.In.fReserved0 && !pReq->u.In.fReserved1,
+ ("SUP_IOCTL_PAGE_ALLOC_EX: fReserved0=%d fReserved1=%d\n", pReq->u.In.fReserved0, pReq->u.In.fReserved1));
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0PageAllocEx(pSession, pReq->u.In.cPages, 0 /* fFlags */,
+ pReq->u.In.fUserMapping ? &pReq->u.Out.pvR3 : NULL,
+ pReq->u.In.fKernelMapping ? &pReq->u.Out.pvR0 : NULL,
+ &pReq->u.Out.aPages[0]);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_MAP_KERNEL):
+ {
+ /* validate */
+ PSUPPAGEMAPKERNEL pReq = (PSUPPAGEMAPKERNEL)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_PAGE_MAP_KERNEL);
+ REQ_CHECK_EXPR_FMT(!pReq->u.In.fFlags, ("SUP_IOCTL_PAGE_MAP_KERNEL: fFlags=%#x! MBZ\n", pReq->u.In.fFlags));
+ REQ_CHECK_EXPR_FMT(!(pReq->u.In.offSub & PAGE_OFFSET_MASK), ("SUP_IOCTL_PAGE_MAP_KERNEL: offSub=%#x\n", pReq->u.In.offSub));
+ REQ_CHECK_EXPR_FMT(pReq->u.In.cbSub && !(pReq->u.In.cbSub & PAGE_OFFSET_MASK),
+ ("SUP_IOCTL_PAGE_MAP_KERNEL: cbSub=%#x\n", pReq->u.In.cbSub));
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0PageMapKernel(pSession, pReq->u.In.pvR3, pReq->u.In.offSub, pReq->u.In.cbSub,
+ pReq->u.In.fFlags, &pReq->u.Out.pvR0);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ pReq->Hdr.cbOut = sizeof(pReq->Hdr);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_PAGE_FREE):
+ {
+ /* validate */
+ PSUPPAGEFREE pReq = (PSUPPAGEFREE)pReqHdr;
+ REQ_CHECK_SIZES(SUP_IOCTL_PAGE_FREE);
+
+ /* execute */
+ pReq->Hdr.rc = SUPR0PageFree(pSession, pReq->u.In.pvR3);
+ return 0;
+ }
+
+ case SUP_CTL_CODE_NO_SIZE(SUP_IOCTL_CALL_SERVICE(0)):
+ {
+ /* validate */
+ PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)pReqHdr;
+ Log4(("SUP_IOCTL_CALL_SERVICE: op=%u in=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ pReq->u.In.uOperation, pReq->Hdr.cbIn, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+
+ if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_SERVICE_SIZE(0))
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_SERVICE, SUP_IOCTL_CALL_SERVICE_SIZE_IN(0), SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0));
+ else
+ {
+ PSUPR0SERVICEREQHDR pSrvReq = (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0];
+ REQ_CHECK_EXPR_FMT(pReq->Hdr.cbIn >= SUP_IOCTL_CALL_SERVICE_SIZE(sizeof(SUPR0SERVICEREQHDR)),
+ ("SUP_IOCTL_CALL_SERVICE: cbIn=%#x < %#lx\n", pReq->Hdr.cbIn, SUP_IOCTL_CALL_SERVICE_SIZE(sizeof(SUPR0SERVICEREQHDR))));
+ REQ_CHECK_EXPR(SUP_IOCTL_CALL_SERVICE, pSrvReq->u32Magic == SUPR0SERVICEREQHDR_MAGIC);
+ REQ_CHECK_SIZES_EX(SUP_IOCTL_CALL_SERVICE, SUP_IOCTL_CALL_SERVICE_SIZE_IN(pSrvReq->cbReq), SUP_IOCTL_CALL_SERVICE_SIZE_OUT(pSrvReq->cbReq));
+ }
+ REQ_CHECK_EXPR(SUP_IOCTL_CALL_SERVICE, memchr(pReq->u.In.szName, '\0', sizeof(pReq->u.In.szName)));
+
+ /* execute */
+ pReq->Hdr.rc = supdrvIOCtl_CallServiceModule(pDevExt, pSession, pReq);
+ return 0;
+ }
+
+ default:
+ Log(("Unknown IOCTL %#lx\n", (long)uIOCtl));
+ break;
+ }
+ return SUPDRV_ERR_GENERAL_FAILURE;
+}
+
+
+/**
+ * Inter-Driver Communcation (IDC) worker.
+ *
+ * @returns VBox status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_INVALID_PARAMETER if the request is invalid.
+ * @retval VERR_NOT_SUPPORTED if the request isn't supported.
+ *
+ * @param uReq The request (function) code.
+ * @param pDevExt Device extention.
+ * @param pSession Session data.
+ * @param pReqHdr The request header.
+ */
+int VBOXCALL supdrvIDC(uintptr_t uReq, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQHDR pReqHdr)
+{
+ /*
+ * The OS specific code has already validated the pSession
+ * pointer, and the request size being greater or equal to
+ * size of the header.
+ *
+ * So, just check that pSession is a kernel context session.
+ */
+ if (RT_UNLIKELY( pSession
+ && pSession->R0Process != NIL_RTR0PROCESS))
+ return VERR_INVALID_PARAMETER;
+
+/*
+ * Validation macro.
+ */
+#define REQ_CHECK_IDC_SIZE(Name, cbExpect) \
+ do { \
+ if (RT_UNLIKELY(pReqHdr->cb != (cbExpect))) \
+ { \
+ OSDBGPRINT(( #Name ": Invalid input/output sizes. cb=%ld expected %ld.\n", \
+ (long)pReqHdr->cb, (long)(cbExpect))); \
+ return pReqHdr->rc = VERR_INVALID_PARAMETER; \
+ } \
+ } while (0)
+
+ switch (uReq)
+ {
+ case SUPDRV_IDC_REQ_CONNECT:
+ {
+ PSUPDRVIDCREQCONNECT pReq = (PSUPDRVIDCREQCONNECT)pReqHdr;
+ REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_CONNECT, sizeof(*pReq));
+
+ /*
+ * Validate the cookie and other input.
+ */
+ if (pReq->Hdr.pSession != NULL)
+ {
+ OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: pSession=%p expected NULL!\n", pReq->Hdr.pSession));
+ return pReqHdr->rc = VERR_INVALID_PARAMETER;
+ }
+ if (pReq->u.In.u32MagicCookie != SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE)
+ {
+ OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: u32MagicCookie=%#x expected %#x!\n",
+ pReq->u.In.u32MagicCookie, SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE));
+ return pReqHdr->rc = VERR_INVALID_PARAMETER;
+ }
+ if ( pReq->u.In.uMinVersion > pReq->u.In.uReqVersion
+ || (pReq->u.In.uMinVersion & UINT32_C(0xffff0000)) != (pReq->u.In.uReqVersion & UINT32_C(0xffff0000)))
+ {
+ OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: uMinVersion=%#x uMaxVersion=%#x doesn't match!\n",
+ pReq->u.In.uMinVersion, pReq->u.In.uReqVersion));
+ return pReqHdr->rc = VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Match the version.
+ * The current logic is very simple, match the major interface version.
+ */
+ if ( pReq->u.In.uMinVersion > SUPDRV_IDC_VERSION
+ || (pReq->u.In.uMinVersion & 0xffff0000) != (SUPDRV_IDC_VERSION & 0xffff0000))
+ {
+ OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: Version mismatch. Requested: %#x Min: %#x Current: %#x\n",
+ pReq->u.In.uReqVersion, pReq->u.In.uMinVersion, SUPDRV_IDC_VERSION));
+ pReq->u.Out.pSession = NULL;
+ pReq->u.Out.uSessionVersion = 0xffffffff;
+ pReq->u.Out.uDriverVersion = SUPDRV_IDC_VERSION;
+ pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
+ pReq->Hdr.rc = VERR_VERSION_MISMATCH;
+ return VINF_SUCCESS;
+ }
+
+ pReq->u.Out.pSession = NULL;
+ pReq->u.Out.uSessionVersion = SUPDRV_IDC_VERSION;
+ pReq->u.Out.uDriverVersion = SUPDRV_IDC_VERSION;
+ pReq->u.Out.uDriverRevision = VBOX_SVN_REV;
+
+ /*
+ * On NT we will already have a session associated with the
+ * client, just like with the SUP_IOCTL_COOKIE request, while
+ * the other doesn't.
+ */
+#ifdef RT_OS_WINDOWS
+ pReq->Hdr.rc = VINF_SUCCESS;
+#else
+ AssertReturn(!pSession, VERR_INTERNAL_ERROR);
+ pReq->Hdr.rc = supdrvCreateSession(pDevExt, false /* fUser */, &pSession);
+ if (RT_FAILURE(pReq->Hdr.rc))
+ {
+ OSDBGPRINT(("SUPDRV_IDC_REQ_CONNECT: failed to create session, rc=%d\n", pReq->Hdr.rc));
+ return VINF_SUCCESS;
+ }
+#endif
+
+ pReq->u.Out.pSession = pSession;
+ pReq->Hdr.pSession = pSession;
+
+ return VINF_SUCCESS;
+ }
+
+ case SUPDRV_IDC_REQ_DISCONNECT:
+ {
+ REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_DISCONNECT, sizeof(*pReqHdr));
+
+#ifdef RT_OS_WINDOWS
+ /* Windows will destroy the session when the file object is destroyed. */
+#else
+ supdrvCloseSession(pDevExt, pSession);
+#endif
+ return pReqHdr->rc = VINF_SUCCESS;
+ }
+
+ case SUPDRV_IDC_REQ_GET_SYMBOL:
+ {
+ PSUPDRVIDCREQGETSYM pReq = (PSUPDRVIDCREQGETSYM)pReqHdr;
+ REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_GET_SYMBOL, sizeof(*pReq));
+
+ pReq->Hdr.rc = supdrvIDC_LdrGetSymbol(pDevExt, pSession, pReq);
+ return VINF_SUCCESS;
+ }
+
+ case SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY:
+ {
+ PSUPDRVIDCREQCOMPREGFACTORY pReq = (PSUPDRVIDCREQCOMPREGFACTORY)pReqHdr;
+ REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY, sizeof(*pReq));
+
+ pReq->Hdr.rc = SUPR0ComponentRegisterFactory(pSession, pReq->u.In.pFactory);
+ return VINF_SUCCESS;
+ }
+
+ case SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY:
+ {
+ PSUPDRVIDCREQCOMPDEREGFACTORY pReq = (PSUPDRVIDCREQCOMPDEREGFACTORY)pReqHdr;
+ REQ_CHECK_IDC_SIZE(SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY, sizeof(*pReq));
+
+ pReq->Hdr.rc = SUPR0ComponentDeregisterFactory(pSession, pReq->u.In.pFactory);
+ return VINF_SUCCESS;
+ }
+
+ default:
+ Log(("Unknown IDC %#lx\n", (long)uReq));
+ break;
+ }
+
+#undef REQ_CHECK_IDC_SIZE
+ return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * Register a object for reference counting.
+ * The object is registered with one reference in the specified session.
+ *
+ * @returns Unique identifier on success (pointer).
+ * All future reference must use this identifier.
+ * @returns NULL on failure.
+ * @param pfnDestructor The destructore function which will be called when the reference count reaches 0.
+ * @param pvUser1 The first user argument.
+ * @param pvUser2 The second user argument.
+ */
+SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
+{
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ PSUPDRVOBJ pObj;
+ PSUPDRVUSAGE pUsage;
+
+ /*
+ * Validate the input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
+ AssertReturn(enmType > SUPDRVOBJTYPE_INVALID && enmType < SUPDRVOBJTYPE_END, NULL);
+ AssertPtrReturn(pfnDestructor, NULL);
+
+ /*
+ * Allocate and initialize the object.
+ */
+ pObj = (PSUPDRVOBJ)RTMemAlloc(sizeof(*pObj));
+ if (!pObj)
+ return NULL;
+ pObj->u32Magic = SUPDRVOBJ_MAGIC;
+ pObj->enmType = enmType;
+ pObj->pNext = NULL;
+ pObj->cUsage = 1;
+ pObj->pfnDestructor = pfnDestructor;
+ pObj->pvUser1 = pvUser1;
+ pObj->pvUser2 = pvUser2;
+ pObj->CreatorUid = pSession->Uid;
+ pObj->CreatorGid = pSession->Gid;
+ pObj->CreatorProcess= pSession->Process;
+ supdrvOSObjInitCreator(pObj, pSession);
+
+ /*
+ * Allocate the usage record.
+ * (We keep freed usage records around to simplify SUPR0ObjAddRefEx().)
+ */
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+
+ pUsage = pDevExt->pUsageFree;
+ if (pUsage)
+ pDevExt->pUsageFree = pUsage->pNext;
+ else
+ {
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ pUsage = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsage));
+ if (!pUsage)
+ {
+ RTMemFree(pObj);
+ return NULL;
+ }
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+ }
+
+ /*
+ * Insert the object and create the session usage record.
+ */
+ /* The object. */
+ pObj->pNext = pDevExt->pObjs;
+ pDevExt->pObjs = pObj;
+
+ /* The session record. */
+ pUsage->cUsage = 1;
+ pUsage->pObj = pObj;
+ pUsage->pNext = pSession->pUsage;
+ /* Log2(("SUPR0ObjRegister: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext)); */
+ pSession->pUsage = pUsage;
+
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ Log(("SUPR0ObjRegister: returns %p (pvUser1=%p, pvUser=%p)\n", pObj, pvUser1, pvUser2));
+ return pObj;
+}
+
+
+/**
+ * Increment the reference counter for the object associating the reference
+ * with the specified session.
+ *
+ * @returns IPRT status code.
+ * @param pvObj The identifier returned by SUPR0ObjRegister().
+ * @param pSession The session which is referencing the object.
+ *
+ * @remarks The caller should not own any spinlocks and must carefully protect
+ * itself against potential race with the destructor so freed memory
+ * isn't accessed here.
+ */
+SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
+{
+ return SUPR0ObjAddRefEx(pvObj, pSession, false /* fNoBlocking */);
+}
+
+
+/**
+ * Increment the reference counter for the object associating the reference
+ * with the specified session.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_TRY_AGAIN if fNoBlocking was set and a new usage record
+ * couldn't be allocated. (If you see this you're not doing the right
+ * thing and it won't ever work reliably.)
+ *
+ * @param pvObj The identifier returned by SUPR0ObjRegister().
+ * @param pSession The session which is referencing the object.
+ * @param fNoBlocking Set if it's not OK to block. Never try to make the
+ * first reference to an object in a session with this
+ * argument set.
+ *
+ * @remarks The caller should not own any spinlocks and must carefully protect
+ * itself against potential race with the destructor so freed memory
+ * isn't accessed here.
+ */
+SUPR0DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
+{
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
+ int rc = VINF_SUCCESS;
+ PSUPDRVUSAGE pUsagePre;
+ PSUPDRVUSAGE pUsage;
+
+ /*
+ * Validate the input.
+ * Be ready for the destruction race (someone might be stuck in the
+ * destructor waiting a lock we own).
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pObj, VERR_INVALID_POINTER);
+ AssertMsgReturn(pObj->u32Magic == SUPDRVOBJ_MAGIC || pObj->u32Magic == SUPDRVOBJ_MAGIC_DEAD,
+ ("Invalid pvObj=%p magic=%#x (expected %#x or %#x)\n", pvObj, pObj->u32Magic, SUPDRVOBJ_MAGIC, SUPDRVOBJ_MAGIC_DEAD),
+ VERR_INVALID_PARAMETER);
+
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+
+ if (RT_UNLIKELY(pObj->u32Magic != SUPDRVOBJ_MAGIC))
+ {
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ AssertMsgFailed(("pvObj=%p magic=%#x\n", pvObj, pObj->u32Magic));
+ return VERR_WRONG_ORDER;
+ }
+
+ /*
+ * Preallocate the usage record if we can.
+ */
+ pUsagePre = pDevExt->pUsageFree;
+ if (pUsagePre)
+ pDevExt->pUsageFree = pUsagePre->pNext;
+ else if (!fNoBlocking)
+ {
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ pUsagePre = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsagePre));
+ if (!pUsagePre)
+ return VERR_NO_MEMORY;
+
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+ if (RT_UNLIKELY(pObj->u32Magic != SUPDRVOBJ_MAGIC))
+ {
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ AssertMsgFailed(("pvObj=%p magic=%#x\n", pvObj, pObj->u32Magic));
+ return VERR_WRONG_ORDER;
+ }
+ }
+
+ /*
+ * Reference the object.
+ */
+ pObj->cUsage++;
+
+ /*
+ * Look for the session record.
+ */
+ for (pUsage = pSession->pUsage; pUsage; pUsage = pUsage->pNext)
+ {
+ /*Log(("SUPR0AddRef: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));*/
+ if (pUsage->pObj == pObj)
+ break;
+ }
+ if (pUsage)
+ pUsage->cUsage++;
+ else if (pUsagePre)
+ {
+ /* create a new session record. */
+ pUsagePre->cUsage = 1;
+ pUsagePre->pObj = pObj;
+ pUsagePre->pNext = pSession->pUsage;
+ pSession->pUsage = pUsagePre;
+ /*Log(("SUPR0AddRef: pUsagePre=%p:{.pObj=%p, .pNext=%p}\n", pUsagePre, pUsagePre->pObj, pUsagePre->pNext));*/
+
+ pUsagePre = NULL;
+ }
+ else
+ {
+ pObj->cUsage--;
+ rc = VERR_TRY_AGAIN;
+ }
+
+ /*
+ * Put any unused usage record into the free list..
+ */
+ if (pUsagePre)
+ {
+ pUsagePre->pNext = pDevExt->pUsageFree;
+ pDevExt->pUsageFree = pUsagePre;
+ }
+
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ return rc;
+}
+
+
+/**
+ * Decrement / destroy a reference counter record for an object.
+ *
+ * The object is uniquely identified by pfnDestructor+pvUser1+pvUser2.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_SUCCESS if not destroyed.
+ * @retval VINF_OBJECT_DESTROYED if it's destroyed by this release call.
+ * @retval VERR_INVALID_PARAMETER if the object isn't valid. Will assert in
+ * string builds.
+ *
+ * @param pvObj The identifier returned by SUPR0ObjRegister().
+ * @param pSession The session which is referencing the object.
+ */
+SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
+{
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
+ int rc = VERR_INVALID_PARAMETER;
+ PSUPDRVUSAGE pUsage;
+ PSUPDRVUSAGE pUsagePrev;
+
+ /*
+ * Validate the input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
+ ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Acquire the spinlock and look for the usage record.
+ */
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+
+ for (pUsagePrev = NULL, pUsage = pSession->pUsage;
+ pUsage;
+ pUsagePrev = pUsage, pUsage = pUsage->pNext)
+ {
+ /*Log2(("SUPR0ObjRelease: pUsage=%p:{.pObj=%p, .pNext=%p}\n", pUsage, pUsage->pObj, pUsage->pNext));*/
+ if (pUsage->pObj == pObj)
+ {
+ rc = VINF_SUCCESS;
+ AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
+ if (pUsage->cUsage > 1)
+ {
+ pObj->cUsage--;
+ pUsage->cUsage--;
+ }
+ else
+ {
+ /*
+ * Free the session record.
+ */
+ if (pUsagePrev)
+ pUsagePrev->pNext = pUsage->pNext;
+ else
+ pSession->pUsage = pUsage->pNext;
+ pUsage->pNext = pDevExt->pUsageFree;
+ pDevExt->pUsageFree = pUsage;
+
+ /* What about the object? */
+ if (pObj->cUsage > 1)
+ pObj->cUsage--;
+ else
+ {
+ /*
+ * Object is to be destroyed, unlink it.
+ */
+ pObj->u32Magic = SUPDRVOBJ_MAGIC_DEAD;
+ rc = VINF_OBJECT_DESTROYED;
+ if (pDevExt->pObjs == pObj)
+ pDevExt->pObjs = pObj->pNext;
+ else
+ {
+ PSUPDRVOBJ pObjPrev;
+ for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
+ if (pObjPrev->pNext == pObj)
+ {
+ pObjPrev->pNext = pObj->pNext;
+ break;
+ }
+ Assert(pObjPrev);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+
+ /*
+ * Call the destructor and free the object if required.
+ */
+ if (rc == VINF_OBJECT_DESTROYED)
+ {
+ Log(("SUPR0ObjRelease: destroying %p/%d (%p/%p) cpid=%RTproc pid=%RTproc dtor=%p\n",
+ pObj, pObj->enmType, pObj->pvUser1, pObj->pvUser2, pObj->CreatorProcess, RTProcSelf(), pObj->pfnDestructor));
+ if (pObj->pfnDestructor)
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapObjDestructor((PFNRT)pObj->pfnDestructor, pObj, pObj->pvUser1, pObj->pvUser2);
+#else
+ pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
+#endif
+ RTMemFree(pObj);
+ }
+
+ AssertMsg(pUsage, ("pvObj=%p\n", pvObj));
+ return rc;
+}
+
+
+/**
+ * Verifies that the current process can access the specified object.
+ *
+ * @returns The following IPRT status code:
+ * @retval VINF_SUCCESS if access was granted.
+ * @retval VERR_PERMISSION_DENIED if denied access.
+ * @retval VERR_INVALID_PARAMETER if invalid parameter.
+ *
+ * @param pvObj The identifier returned by SUPR0ObjRegister().
+ * @param pSession The session which wishes to access the object.
+ * @param pszObjName Object string name. This is optional and depends on the object type.
+ *
+ * @remark The caller is responsible for making sure the object isn't removed while
+ * we're inside this function. If uncertain about this, just call AddRef before calling us.
+ */
+SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
+{
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
+ int rc;
+
+ /*
+ * Validate the input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertMsgReturn(VALID_PTR(pObj) && pObj->u32Magic == SUPDRVOBJ_MAGIC,
+ ("Invalid pvObj=%p magic=%#x (exepcted %#x)\n", pvObj, pObj ? pObj->u32Magic : 0, SUPDRVOBJ_MAGIC),
+ VERR_INVALID_PARAMETER);
+
+ /*
+ * Check access. (returns true if a decision has been made.)
+ */
+ rc = VERR_INTERNAL_ERROR;
+ if (supdrvOSObjCanAccess(pObj, pSession, pszObjName, &rc))
+ return rc;
+
+ /*
+ * Default policy is to allow the user to access his own
+ * stuff but nothing else.
+ */
+ if (pObj->CreatorUid == pSession->Uid)
+ return VINF_SUCCESS;
+ return VERR_PERMISSION_DENIED;
+}
+
+
+/**
+ * Lock pages.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session to which the locked memory should be associated.
+ * @param pvR3 Start of the memory range to lock.
+ * This must be page aligned.
+ * @param cb Size of the memory range to lock.
+ * This must be page aligned.
+ */
+SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
+{
+ int rc;
+ SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
+ const size_t cb = (size_t)cPages << PAGE_SHIFT;
+ LogFlow(("SUPR0LockMem: pSession=%p pvR3=%p cPages=%d paPages=%p\n", pSession, (void *)pvR3, cPages, paPages));
+
+ /*
+ * Verify input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
+ if ( RT_ALIGN_R3PT(pvR3, PAGE_SIZE, RTR3PTR) != pvR3
+ || !pvR3)
+ {
+ Log(("pvR3 (%p) must be page aligned and not NULL!\n", (void *)pvR3));
+ return VERR_INVALID_PARAMETER;
+ }
+
+#ifdef RT_OS_WINDOWS /* A temporary hack for windows, will be removed once all ring-3 code has been cleaned up. */
+ /* First check if we allocated it using SUPPageAlloc; if so then we don't need to lock it again */
+ rc = supdrvPageGetPhys(pSession, pvR3, cPages, paPages);
+ if (RT_SUCCESS(rc))
+ return rc;
+#endif
+
+ /*
+ * Let IPRT do the job.
+ */
+ Mem.eType = MEMREF_TYPE_LOCKED;
+ rc = RTR0MemObjLockUser(&Mem.MemObj, pvR3, cb, RTR0ProcHandleSelf());
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t iPage = cPages;
+ AssertMsg(RTR0MemObjAddressR3(Mem.MemObj) == pvR3, ("%p == %p\n", RTR0MemObjAddressR3(Mem.MemObj), pvR3));
+ AssertMsg(RTR0MemObjSize(Mem.MemObj) == cb, ("%x == %x\n", RTR0MemObjSize(Mem.MemObj), cb));
+
+ while (iPage-- > 0)
+ {
+ paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
+ if (RT_UNLIKELY(paPages[iPage] == NIL_RTCCPHYS))
+ {
+ AssertMsgFailed(("iPage=%d\n", iPage));
+ rc = VERR_INTERNAL_ERROR;
+ break;
+ }
+ }
+ if (RT_SUCCESS(rc))
+ rc = supdrvMemAdd(&Mem, pSession);
+ if (RT_FAILURE(rc))
+ {
+ int rc2 = RTR0MemObjFree(Mem.MemObj, false);
+ AssertRC(rc2);
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * Unlocks the memory pointed to by pv.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session to which the memory was locked.
+ * @param pvR3 Memory to unlock.
+ */
+SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3)
+{
+ LogFlow(("SUPR0UnlockMem: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+#ifdef RT_OS_WINDOWS
+ /*
+ * Temporary hack for windows - SUPR0PageFree will unlock SUPR0PageAlloc
+ * allocations; ignore this call.
+ */
+ if (supdrvPageWasLockedByPageAlloc(pSession, pvR3))
+ {
+ LogFlow(("Page will be unlocked in SUPR0PageFree -> ignore\n"));
+ return VINF_SUCCESS;
+ }
+#endif
+ return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_LOCKED);
+}
+
+
+/**
+ * Allocates a chunk of page aligned memory with contiguous and fixed physical
+ * backing.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session data.
+ * @param cb Number of bytes to allocate.
+ * @param ppvR0 Where to put the address of Ring-0 mapping the allocated memory.
+ * @param ppvR3 Where to put the address of Ring-3 mapping the allocated memory.
+ * @param pHCPhys Where to put the physical address of allocated memory.
+ */
+SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
+{
+ int rc;
+ SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
+ LogFlow(("SUPR0ContAlloc: pSession=%p cPages=%d ppvR0=%p ppvR3=%p pHCPhys=%p\n", pSession, cPages, ppvR0, ppvR3, pHCPhys));
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ if (!ppvR3 || !ppvR0 || !pHCPhys)
+ {
+ Log(("Null pointer. All of these should be set: pSession=%p ppvR0=%p ppvR3=%p pHCPhys=%p\n",
+ pSession, ppvR0, ppvR3, pHCPhys));
+ return VERR_INVALID_PARAMETER;
+
+ }
+ if (cPages < 1 || cPages >= 256)
+ {
+ Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256.\n", cPages));
+ return VERR_PAGE_COUNT_OUT_OF_RANGE;
+ }
+
+ /*
+ * Let IPRT do the job.
+ */
+ rc = RTR0MemObjAllocCont(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable R0 mapping */);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2;
+ rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
+ RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
+ if (RT_SUCCESS(rc))
+ {
+ Mem.eType = MEMREF_TYPE_CONT;
+ rc = supdrvMemAdd(&Mem, pSession);
+ if (!rc)
+ {
+ *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
+ *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
+ *pHCPhys = RTR0MemObjGetPagePhysAddr(Mem.MemObj, 0);
+ return 0;
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
+ AssertRC(rc2);
+ }
+ rc2 = RTR0MemObjFree(Mem.MemObj, false);
+ AssertRC(rc2);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Frees memory allocated using SUPR0ContAlloc().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to which the memory was allocated.
+ * @param uPtr Pointer to the memory (ring-3 or ring-0).
+ */
+SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
+{
+ LogFlow(("SUPR0ContFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_CONT);
+}
+
+
+/**
+ * Allocates a chunk of page aligned memory with fixed physical backing below 4GB.
+ *
+ * The memory isn't zeroed.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session data.
+ * @param cPages Number of pages to allocate.
+ * @param ppvR0 Where to put the address of Ring-0 mapping of the allocated memory.
+ * @param ppvR3 Where to put the address of Ring-3 mapping of the allocated memory.
+ * @param paPages Where to put the physical addresses of allocated memory.
+ */
+SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages)
+{
+ unsigned iPage;
+ int rc;
+ SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
+ LogFlow(("SUPR0LowAlloc: pSession=%p cPages=%d ppvR3=%p ppvR0=%p paPages=%p\n", pSession, cPages, ppvR3, ppvR0, paPages));
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ if (!ppvR3 || !ppvR0 || !paPages)
+ {
+ Log(("Null pointer. All of these should be set: pSession=%p ppvR3=%p ppvR0=%p paPages=%p\n",
+ pSession, ppvR3, ppvR0, paPages));
+ return VERR_INVALID_PARAMETER;
+
+ }
+ if (cPages < 1 || cPages >= 256)
+ {
+ Log(("Illegal request cPages=%d, must be greater than 0 and smaller than 256.\n", cPages));
+ return VERR_PAGE_COUNT_OUT_OF_RANGE;
+ }
+
+ /*
+ * Let IPRT do the work.
+ */
+ rc = RTR0MemObjAllocLow(&Mem.MemObj, cPages << PAGE_SHIFT, true /* executable ring-0 mapping */);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2;
+ rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
+ RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
+ if (RT_SUCCESS(rc))
+ {
+ Mem.eType = MEMREF_TYPE_LOW;
+ rc = supdrvMemAdd(&Mem, pSession);
+ if (!rc)
+ {
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MemObj, iPage);
+ AssertMsg(!(paPages[iPage] & (PAGE_SIZE - 1)), ("iPage=%d Phys=%RHp\n", paPages[iPage]));
+ }
+ *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
+ *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
+ return 0;
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
+ AssertRC(rc2);
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MemObj, false);
+ AssertRC(rc2);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Frees memory allocated using SUPR0LowAlloc().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to which the memory was allocated.
+ * @param uPtr Pointer to the memory (ring-3 or ring-0).
+ */
+SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
+{
+ LogFlow(("SUPR0LowFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_LOW);
+}
+
+
+
+/**
+ * Allocates a chunk of memory with both R0 and R3 mappings.
+ * The memory is fixed and it's possible to query the physical addresses using SUPR0MemGetPhys().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to associated the allocation with.
+ * @param cb Number of bytes to allocate.
+ * @param ppvR0 Where to store the address of the Ring-0 mapping.
+ * @param ppvR3 Where to store the address of the Ring-3 mapping.
+ */
+SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
+{
+ int rc;
+ SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
+ LogFlow(("SUPR0MemAlloc: pSession=%p cb=%d ppvR0=%p ppvR3=%p\n", pSession, cb, ppvR0, ppvR3));
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(ppvR0, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppvR3, VERR_INVALID_POINTER);
+ if (cb < 1 || cb >= _4M)
+ {
+ Log(("Illegal request cb=%u; must be greater than 0 and smaller than 4MB.\n", cb));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Let IPRT do the work.
+ */
+ rc = RTR0MemObjAllocPage(&Mem.MemObj, cb, true /* executable ring-0 mapping */);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2;
+ rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
+ RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
+ if (RT_SUCCESS(rc))
+ {
+ Mem.eType = MEMREF_TYPE_MEM;
+ rc = supdrvMemAdd(&Mem, pSession);
+ if (!rc)
+ {
+ *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
+ *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
+ return VINF_SUCCESS;
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
+ AssertRC(rc2);
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MemObj, false);
+ AssertRC(rc2);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Get the physical addresses of memory allocated using SUPR0MemAlloc().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to which the memory was allocated.
+ * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
+ * @param paPages Where to store the physical addresses.
+ */
+SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages) /** @todo switch this bugger to RTHCPHYS */
+{
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ LogFlow(("SUPR0MemGetPhys: pSession=%p uPtr=%p paPages=%p\n", pSession, (void *)uPtr, paPages));
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(paPages, VERR_INVALID_POINTER);
+ AssertReturn(uPtr, VERR_INVALID_PARAMETER);
+
+ /*
+ * Search for the address.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed > 0)
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if ( pBundle->aMem[i].eType == MEMREF_TYPE_MEM
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
+ || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr)
+ )
+ )
+ {
+ const size_t cPages = RTR0MemObjSize(pBundle->aMem[i].MemObj) >> PAGE_SHIFT;
+ size_t iPage;
+ for (iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].Phys = RTR0MemObjGetPagePhysAddr(pBundle->aMem[i].MemObj, iPage);
+ paPages[iPage].uReserved = 0;
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return VINF_SUCCESS;
+ }
+ }
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ Log(("Failed to find %p!!!\n", (void *)uPtr));
+ return VERR_INVALID_PARAMETER;
+}
+
+
+/**
+ * Free memory allocated by SUPR0MemAlloc().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session owning the allocation.
+ * @param uPtr The Ring-0 or Ring-3 address returned by SUPR0MemAlloc().
+ */
+SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
+{
+ LogFlow(("SUPR0MemFree: pSession=%p uPtr=%p\n", pSession, (void *)uPtr));
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ return supdrvMemRelease(pSession, uPtr, MEMREF_TYPE_MEM);
+}
+
+
+/**
+ * Allocates a chunk of memory with only a R3 mappings.
+ *
+ * The memory is fixed and it's possible to query the physical addresses using
+ * SUPR0MemGetPhys().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to associated the allocation with.
+ * @param cPages The number of pages to allocate.
+ * @param ppvR3 Where to store the address of the Ring-3 mapping.
+ * @param paPages Where to store the addresses of the pages. Optional.
+ */
+SUPR0DECL(int) SUPR0PageAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR3PTR ppvR3, PRTHCPHYS paPages)
+{
+ AssertPtrReturn(ppvR3, VERR_INVALID_POINTER);
+ return SUPR0PageAllocEx(pSession, cPages, 0 /*fFlags*/, ppvR3, NULL, paPages);
+}
+
+
+/**
+ * Allocates a chunk of memory with a kernel or/and a user mode mapping.
+ *
+ * The memory is fixed and it's possible to query the physical addresses using
+ * SUPR0MemGetPhys().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to associated the allocation with.
+ * @param cPages The number of pages to allocate.
+ * @param fFlags Flags, reserved for the future. Must be zero.
+ * @param ppvR3 Where to store the address of the Ring-3 mapping.
+ * NULL if no ring-3 mapping.
+ * @param ppvR3 Where to store the address of the Ring-0 mapping.
+ * NULL if no ring-0 mapping.
+ * @param paPages Where to store the addresses of the pages. Optional.
+ */
+SUPR0DECL(int) SUPR0PageAllocEx(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages)
+{
+ int rc;
+ SUPDRVMEMREF Mem = { NIL_RTR0MEMOBJ, NIL_RTR0MEMOBJ, MEMREF_TYPE_UNUSED };
+ LogFlow(("SUPR0PageAlloc: pSession=%p cb=%d ppvR3=%p\n", pSession, cPages, ppvR3));
+
+ /*
+ * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(ppvR3, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(ppvR0, VERR_INVALID_POINTER);
+ AssertReturn(ppvR3 || ppvR0, VERR_INVALID_PARAMETER);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+ if (cPages < 1 || cPages > VBOX_MAX_ALLOC_PAGE_COUNT)
+ {
+ Log(("SUPR0PageAlloc: Illegal request cb=%u; must be greater than 0 and smaller than 128MB.\n", cPages));
+ return VERR_PAGE_COUNT_OUT_OF_RANGE;
+ }
+
+ /*
+ * Let IPRT do the work.
+ */
+ if (ppvR0)
+ rc = RTR0MemObjAllocPage(&Mem.MemObj, (size_t)cPages * PAGE_SIZE, true /* fExecutable */);
+ else
+ rc = RTR0MemObjAllocPhysNC(&Mem.MemObj, (size_t)cPages * PAGE_SIZE, NIL_RTHCPHYS);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2;
+ if (ppvR3)
+ rc = RTR0MemObjMapUser(&Mem.MapObjR3, Mem.MemObj, (RTR3PTR)-1, 0,
+ RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ, RTR0ProcHandleSelf());
+ else
+ Mem.MapObjR3 = NIL_RTR0MEMOBJ;
+ if (RT_SUCCESS(rc))
+ {
+ Mem.eType = MEMREF_TYPE_PAGE;
+ rc = supdrvMemAdd(&Mem, pSession);
+ if (!rc)
+ {
+ if (ppvR3)
+ *ppvR3 = RTR0MemObjAddressR3(Mem.MapObjR3);
+ if (ppvR0)
+ *ppvR0 = RTR0MemObjAddress(Mem.MemObj);
+ if (paPages)
+ {
+ uint32_t iPage = cPages;
+ while (iPage-- > 0)
+ {
+ paPages[iPage] = RTR0MemObjGetPagePhysAddr(Mem.MapObjR3, iPage);
+ Assert(paPages[iPage] != NIL_RTHCPHYS);
+ }
+ }
+ return VINF_SUCCESS;
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MapObjR3, false);
+ AssertRC(rc2);
+ }
+
+ rc2 = RTR0MemObjFree(Mem.MemObj, false);
+ AssertRC(rc2);
+ }
+ return rc;
+}
+
+
+/**
+ * Allocates a chunk of memory with a kernel or/and a user mode mapping.
+ *
+ * The memory is fixed and it's possible to query the physical addresses using
+ * SUPR0MemGetPhys().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to associated the allocation with.
+ * @param cPages The number of pages to allocate.
+ * @param fFlags Flags, reserved for the future. Must be zero.
+ * @param ppvR3 Where to store the address of the Ring-3 mapping.
+ * NULL if no ring-3 mapping.
+ * @param ppvR3 Where to store the address of the Ring-0 mapping.
+ * NULL if no ring-0 mapping.
+ * @param paPages Where to store the addresses of the pages. Optional.
+ */
+SUPR0DECL(int) SUPR0PageMapKernel(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t offSub, uint32_t cbSub,
+ uint32_t fFlags, PRTR0PTR ppvR0)
+{
+ int rc;
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ RTR0MEMOBJ hMemObj = NIL_RTR0MEMOBJ;
+ LogFlow(("SUPR0PageMapKernel: pSession=%p pvR3=%p offSub=%#x cbSub=%#x\n", pSession, pvR3, offSub, cbSub));
+
+ /*
+ * Validate input. The allowed allocation size must be at least equal to the maximum guest VRAM size.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(ppvR0, VERR_INVALID_POINTER);
+ AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
+ AssertReturn(!(offSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(!(cbSub & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
+ AssertReturn(cbSub, VERR_INVALID_PARAMETER);
+
+ /*
+ * Find the memory object.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed > 0)
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if ( ( pBundle->aMem[i].eType == MEMREF_TYPE_PAGE
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
+ || ( pBundle->aMem[i].eType == MEMREF_TYPE_LOCKED
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && pBundle->aMem[i].MapObjR3 == NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MemObj) == pvR3))
+ {
+ hMemObj = pBundle->aMem[i].MemObj;
+ break;
+ }
+ }
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+
+ rc = VERR_INVALID_PARAMETER;
+ if (hMemObj != NIL_RTR0MEMOBJ)
+ {
+ /*
+ * Do some furter input validations before calling IPRT.
+ * (Cleanup is done indirectly by telling RTR0MemObjFree to include mappings.)
+ */
+ size_t cbMemObj = RTR0MemObjSize(hMemObj);
+ if ( offSub < cbMemObj
+ && cbSub <= cbMemObj
+ && offSub + cbSub <= cbMemObj)
+ {
+ RTR0MEMOBJ hMapObj;
+ rc = RTR0MemObjMapKernelEx(&hMapObj, hMemObj, (void *)-1, 0,
+ RTMEM_PROT_READ | RTMEM_PROT_WRITE, offSub, cbSub);
+ if (RT_SUCCESS(rc))
+ *ppvR0 = RTR0MemObjAddress(hMapObj);
+ }
+ else
+ SUPR0Printf("SUPR0PageMapKernel: cbMemObj=%#x offSub=%#x cbSub=%#x\n", cbMemObj, offSub, cbSub);
+
+ }
+ return rc;
+}
+
+
+
+#ifdef RT_OS_WINDOWS
+/**
+ * Check if the pages were locked by SUPR0PageAlloc
+ *
+ * This function will be removed along with the lock/unlock hacks when
+ * we've cleaned up the ring-3 code properly.
+ *
+ * @returns boolean
+ * @param pSession The session to which the memory was allocated.
+ * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc().
+ */
+static bool supdrvPageWasLockedByPageAlloc(PSUPDRVSESSION pSession, RTR3PTR pvR3)
+{
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ LogFlow(("SUPR0PageIsLockedByPageAlloc: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
+
+ /*
+ * Search for the address.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed > 0)
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if ( pBundle->aMem[i].eType == MEMREF_TYPE_PAGE
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
+ {
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return true;
+ }
+ }
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return false;
+}
+
+
+/**
+ * Get the physical addresses of memory allocated using SUPR0PageAllocEx().
+ *
+ * This function will be removed along with the lock/unlock hacks when
+ * we've cleaned up the ring-3 code properly.
+ *
+ * @returns IPRT status code.
+ * @param pSession The session to which the memory was allocated.
+ * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc().
+ * @param cPages Number of pages in paPages
+ * @param paPages Where to store the physical addresses.
+ */
+static int supdrvPageGetPhys(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages)
+{
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ LogFlow(("supdrvPageGetPhys: pSession=%p pvR3=%p cPages=%#lx paPages=%p\n", pSession, (void *)pvR3, (long)cPages, paPages));
+
+ /*
+ * Search for the address.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed > 0)
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if ( pBundle->aMem[i].eType == MEMREF_TYPE_PAGE
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == pvR3)
+ {
+ uint32_t iPage;
+ size_t cMaxPages = RTR0MemObjSize(pBundle->aMem[i].MemObj) >> PAGE_SHIFT;
+ cPages = (uint32_t)RT_MIN(cMaxPages, cPages);
+ for (iPage = 0; iPage < cPages; iPage++)
+ paPages[iPage] = RTR0MemObjGetPagePhysAddr(pBundle->aMem[i].MemObj, iPage);
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return VINF_SUCCESS;
+ }
+ }
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return VERR_INVALID_PARAMETER;
+}
+#endif /* RT_OS_WINDOWS */
+
+
+/**
+ * Free memory allocated by SUPR0PageAlloc() and SUPR0PageAllocEx().
+ *
+ * @returns IPRT status code.
+ * @param pSession The session owning the allocation.
+ * @param pvR3 The Ring-3 address returned by SUPR0PageAlloc() or
+ * SUPR0PageAllocEx().
+ */
+SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3)
+{
+ LogFlow(("SUPR0PageFree: pSession=%p pvR3=%p\n", pSession, (void *)pvR3));
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ return supdrvMemRelease(pSession, (RTHCUINTPTR)pvR3, MEMREF_TYPE_PAGE);
+}
+
+
+/**
+ * Maps the GIP into userspace and/or get the physical address of the GIP.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session to which the GIP mapping should belong.
+ * @param ppGipR3 Where to store the address of the ring-3 mapping. (optional)
+ * @param pHCPhysGip Where to store the physical address. (optional)
+ *
+ * @remark There is no reference counting on the mapping, so one call to this function
+ * count globally as one reference. One call to SUPR0GipUnmap() is will unmap GIP
+ * and remove the session as a GIP user.
+ */
+SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip)
+{
+ int rc = 0;
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ RTR3PTR pGip = NIL_RTR3PTR;
+ RTHCPHYS HCPhys = NIL_RTHCPHYS;
+ LogFlow(("SUPR0GipMap: pSession=%p ppGipR3=%p pHCPhysGip=%p\n", pSession, ppGipR3, pHCPhysGip));
+
+ /*
+ * Validate
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertPtrNullReturn(ppGipR3, VERR_INVALID_POINTER);
+ AssertPtrNullReturn(pHCPhysGip, VERR_INVALID_POINTER);
+
+ RTSemFastMutexRequest(pDevExt->mtxGip);
+ if (pDevExt->pGip)
+ {
+ /*
+ * Map it?
+ */
+ if (ppGipR3)
+ {
+ if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
+ rc = RTR0MemObjMapUser(&pSession->GipMapObjR3, pDevExt->GipMemObj, (RTR3PTR)-1, 0,
+ RTMEM_PROT_READ, RTR0ProcHandleSelf());
+ if (RT_SUCCESS(rc))
+ {
+ pGip = RTR0MemObjAddressR3(pSession->GipMapObjR3);
+ rc = VINF_SUCCESS; /** @todo remove this and replace the !rc below with RT_SUCCESS(rc). */
+ }
+ }
+
+ /*
+ * Get physical address.
+ */
+ if (pHCPhysGip && !rc)
+ HCPhys = pDevExt->HCPhysGip;
+
+ /*
+ * Reference globally.
+ */
+ if (!pSession->fGipReferenced && !rc)
+ {
+ pSession->fGipReferenced = 1;
+ pDevExt->cGipUsers++;
+ if (pDevExt->cGipUsers == 1)
+ {
+ PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
+ unsigned i;
+
+ LogFlow(("SUPR0GipMap: Resumes GIP updating\n"));
+
+ for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
+ ASMAtomicXchgU32(&pGip->aCPUs[i].u32TransactionId, pGip->aCPUs[i].u32TransactionId & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
+ ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, 0);
+
+ rc = RTTimerStart(pDevExt->pGipTimer, 0);
+ AssertRC(rc); rc = VINF_SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ rc = SUPDRV_ERR_GENERAL_FAILURE;
+ Log(("SUPR0GipMap: GIP is not available!\n"));
+ }
+ RTSemFastMutexRelease(pDevExt->mtxGip);
+
+ /*
+ * Write returns.
+ */
+ if (pHCPhysGip)
+ *pHCPhysGip = HCPhys;
+ if (ppGipR3)
+ *ppGipR3 = pGip;
+
+#ifdef DEBUG_DARWIN_GIP
+ OSDBGPRINT(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGip=%p GipMapObjR3\n", rc, (unsigned long)HCPhys, pGip, pSession->GipMapObjR3));
+#else
+ LogFlow(("SUPR0GipMap: returns %d *pHCPhysGip=%lx *ppGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)(uintptr_t)pGip));
+#endif
+ return rc;
+}
+
+
+/**
+ * Unmaps any user mapping of the GIP and terminates all GIP access
+ * from this session.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session to which the GIP mapping should belong.
+ */
+SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession)
+{
+ int rc = VINF_SUCCESS;
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+#ifdef DEBUG_DARWIN_GIP
+ OSDBGPRINT(("SUPR0GipUnmap: pSession=%p pGip=%p GipMapObjR3=%p\n",
+ pSession,
+ pSession->GipMapObjR3 != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pSession->GipMapObjR3) : NULL,
+ pSession->GipMapObjR3));
+#else
+ LogFlow(("SUPR0GipUnmap: pSession=%p\n", pSession));
+#endif
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+
+ RTSemFastMutexRequest(pDevExt->mtxGip);
+
+ /*
+ * Unmap anything?
+ */
+ if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
+ {
+ rc = RTR0MemObjFree(pSession->GipMapObjR3, false);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ pSession->GipMapObjR3 = NIL_RTR0MEMOBJ;
+ }
+
+ /*
+ * Dereference global GIP.
+ */
+ if (pSession->fGipReferenced && !rc)
+ {
+ pSession->fGipReferenced = 0;
+ if ( pDevExt->cGipUsers > 0
+ && !--pDevExt->cGipUsers)
+ {
+ LogFlow(("SUPR0GipUnmap: Suspends GIP updating\n"));
+ rc = RTTimerStop(pDevExt->pGipTimer); AssertRC(rc); rc = 0;
+ }
+ }
+
+ RTSemFastMutexRelease(pDevExt->mtxGip);
+
+ return rc;
+}
+
+
+/**
+ * Register a component factory with the support driver.
+ *
+ * This is currently restricted to kernel sessions only.
+ *
+ * @returns VBox status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_NO_MEMORY if we're out of memory.
+ * @retval VERR_ALREADY_EXISTS if the factory has already been registered.
+ * @retval VERR_ACCESS_DENIED if it isn't a kernel session.
+ * @retval VERR_INVALID_PARAMETER on invalid parameter.
+ * @retval VERR_INVALID_POINTER on invalid pointer parameter.
+ *
+ * @param pSession The SUPDRV session (must be a ring-0 session).
+ * @param pFactory Pointer to the component factory registration structure.
+ *
+ * @remarks This interface is also available via SUPR0IdcComponentRegisterFactory.
+ */
+SUPR0DECL(int) SUPR0ComponentRegisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory)
+{
+ PSUPDRVFACTORYREG pNewReg;
+ const char *psz;
+ int rc;
+
+ /*
+ * Validate parameters.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_ACCESS_DENIED);
+ AssertPtrReturn(pFactory, VERR_INVALID_POINTER);
+ AssertPtrReturn(pFactory->pfnQueryFactoryInterface, VERR_INVALID_POINTER);
+ psz = (const char *)memchr(pFactory->szName, '\0', sizeof(pFactory->szName));
+ AssertReturn(psz, VERR_INVALID_PARAMETER);
+
+ /*
+ * Allocate and initialize a new registration structure.
+ */
+ pNewReg = (PSUPDRVFACTORYREG)RTMemAlloc(sizeof(SUPDRVFACTORYREG));
+ if (pNewReg)
+ {
+ pNewReg->pNext = NULL;
+ pNewReg->pFactory = pFactory;
+ pNewReg->pSession = pSession;
+ pNewReg->cchName = psz - &pFactory->szName[0];
+
+ /*
+ * Add it to the tail of the list after checking for prior registration.
+ */
+ rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
+ if (RT_SUCCESS(rc))
+ {
+ PSUPDRVFACTORYREG pPrev = NULL;
+ PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
+ while (pCur && pCur->pFactory != pFactory)
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+ if (!pCur)
+ {
+ if (pPrev)
+ pPrev->pNext = pNewReg;
+ else
+ pSession->pDevExt->pComponentFactoryHead = pNewReg;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_ALREADY_EXISTS;
+
+ RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
+ }
+
+ if (RT_FAILURE(rc))
+ RTMemFree(pNewReg);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+/**
+ * Deregister a component factory.
+ *
+ * @returns VBox status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_NOT_FOUND if the factory wasn't registered.
+ * @retval VERR_ACCESS_DENIED if it isn't a kernel session.
+ * @retval VERR_INVALID_PARAMETER on invalid parameter.
+ * @retval VERR_INVALID_POINTER on invalid pointer parameter.
+ *
+ * @param pSession The SUPDRV session (must be a ring-0 session).
+ * @param pFactory Pointer to the component factory registration structure
+ * previously passed SUPR0ComponentRegisterFactory().
+ *
+ * @remarks This interface is also available via SUPR0IdcComponentDeregisterFactory.
+ */
+SUPR0DECL(int) SUPR0ComponentDeregisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory)
+{
+ int rc;
+
+ /*
+ * Validate parameters.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+ AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_ACCESS_DENIED);
+ AssertPtrReturn(pFactory, VERR_INVALID_POINTER);
+
+ /*
+ * Take the lock and look for the registration record.
+ */
+ rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
+ if (RT_SUCCESS(rc))
+ {
+ PSUPDRVFACTORYREG pPrev = NULL;
+ PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
+ while (pCur && pCur->pFactory != pFactory)
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+ if (pCur)
+ {
+ if (!pPrev)
+ pSession->pDevExt->pComponentFactoryHead = pCur->pNext;
+ else
+ pPrev->pNext = pCur->pNext;
+
+ pCur->pNext = NULL;
+ pCur->pFactory = NULL;
+ pCur->pSession = NULL;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
+
+ RTMemFree(pCur);
+ }
+ return rc;
+}
+
+
+/**
+ * Queries a component factory.
+ *
+ * @returns VBox status code.
+ * @retval VERR_INVALID_PARAMETER on invalid parameter.
+ * @retval VERR_INVALID_POINTER on invalid pointer parameter.
+ * @retval VERR_SUPDRV_COMPONENT_NOT_FOUND if the component factory wasn't found.
+ * @retval VERR_SUPDRV_INTERFACE_NOT_SUPPORTED if the interface wasn't supported.
+ *
+ * @param pSession The SUPDRV session.
+ * @param pszName The name of the component factory.
+ * @param pszInterfaceUuid The UUID of the factory interface (stringified).
+ * @param ppvFactoryIf Where to store the factory interface.
+ */
+SUPR0DECL(int) SUPR0ComponentQueryFactory(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf)
+{
+ const char *pszEnd;
+ size_t cchName;
+ int rc;
+
+ /*
+ * Validate parameters.
+ */
+ AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ pszEnd = memchr(pszName, '\0', RT_SIZEOFMEMB(SUPDRVFACTORY, szName));
+ AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
+ cchName = pszEnd - pszName;
+
+ AssertPtrReturn(pszInterfaceUuid, VERR_INVALID_POINTER);
+ pszEnd = memchr(pszInterfaceUuid, '\0', RTUUID_STR_LENGTH);
+ AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(ppvFactoryIf, VERR_INVALID_POINTER);
+ *ppvFactoryIf = NULL;
+
+ /*
+ * Take the lock and try all factories by this name.
+ */
+ rc = RTSemFastMutexRequest(pSession->pDevExt->mtxComponentFactory);
+ if (RT_SUCCESS(rc))
+ {
+ PSUPDRVFACTORYREG pCur = pSession->pDevExt->pComponentFactoryHead;
+ rc = VERR_SUPDRV_COMPONENT_NOT_FOUND;
+ while (pCur)
+ {
+ if ( pCur->cchName == cchName
+ && !memcmp(pCur->pFactory->szName, pszName, cchName))
+ {
+#ifdef RT_WITH_W64_UNWIND_HACK
+ void *pvFactory = supdrvNtWrapQueryFactoryInterface((PFNRT)pCur->pFactory->pfnQueryFactoryInterface, pCur->pFactory, pSession, pszInterfaceUuid);
+#else
+ void *pvFactory = pCur->pFactory->pfnQueryFactoryInterface(pCur->pFactory, pSession, pszInterfaceUuid);
+#endif
+ if (pvFactory)
+ {
+ *ppvFactoryIf = pvFactory;
+ rc = VINF_SUCCESS;
+ break;
+ }
+ rc = VERR_SUPDRV_INTERFACE_NOT_SUPPORTED;
+ }
+
+ /* next */
+ pCur = pCur->pNext;
+ }
+
+ RTSemFastMutexRelease(pSession->pDevExt->mtxComponentFactory);
+ }
+ return rc;
+}
+
+
+/**
+ * Adds a memory object to the session.
+ *
+ * @returns IPRT status code.
+ * @param pMem Memory tracking structure containing the
+ * information to track.
+ * @param pSession The session.
+ */
+static int supdrvMemAdd(PSUPDRVMEMREF pMem, PSUPDRVSESSION pSession)
+{
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+
+ /*
+ * Find free entry and record the allocation.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed < RT_ELEMENTS(pBundle->aMem))
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if (pBundle->aMem[i].MemObj == NIL_RTR0MEMOBJ)
+ {
+ pBundle->cUsed++;
+ pBundle->aMem[i] = *pMem;
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ return VINF_SUCCESS;
+ }
+ }
+ AssertFailed(); /* !!this can't be happening!!! */
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+
+ /*
+ * Need to allocate a new bundle.
+ * Insert into the last entry in the bundle.
+ */
+ pBundle = (PSUPDRVBUNDLE)RTMemAllocZ(sizeof(*pBundle));
+ if (!pBundle)
+ return VERR_NO_MEMORY;
+
+ /* take last entry. */
+ pBundle->cUsed++;
+ pBundle->aMem[RT_ELEMENTS(pBundle->aMem) - 1] = *pMem;
+
+ /* insert into list. */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ pBundle->pNext = pSession->Bundle.pNext;
+ pSession->Bundle.pNext = pBundle;
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Releases a memory object referenced by pointer and type.
+ *
+ * @returns IPRT status code.
+ * @param pSession Session data.
+ * @param uPtr Pointer to memory. This is matched against both the R0 and R3 addresses.
+ * @param eType Memory type.
+ */
+static int supdrvMemRelease(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, SUPDRVMEMREFTYPE eType)
+{
+ PSUPDRVBUNDLE pBundle;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+
+ /*
+ * Validate input.
+ */
+ if (!uPtr)
+ {
+ Log(("Illegal address %p\n", (void *)uPtr));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Search for the address.
+ */
+ RTSpinlockAcquire(pSession->Spinlock, &SpinlockTmp);
+ for (pBundle = &pSession->Bundle; pBundle; pBundle = pBundle->pNext)
+ {
+ if (pBundle->cUsed > 0)
+ {
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pBundle->aMem); i++)
+ {
+ if ( pBundle->aMem[i].eType == eType
+ && pBundle->aMem[i].MemObj != NIL_RTR0MEMOBJ
+ && ( (RTHCUINTPTR)RTR0MemObjAddress(pBundle->aMem[i].MemObj) == uPtr
+ || ( pBundle->aMem[i].MapObjR3 != NIL_RTR0MEMOBJ
+ && RTR0MemObjAddressR3(pBundle->aMem[i].MapObjR3) == uPtr))
+ )
+ {
+ /* Make a copy of it and release it outside the spinlock. */
+ SUPDRVMEMREF Mem = pBundle->aMem[i];
+ pBundle->aMem[i].eType = MEMREF_TYPE_UNUSED;
+ pBundle->aMem[i].MemObj = NIL_RTR0MEMOBJ;
+ pBundle->aMem[i].MapObjR3 = NIL_RTR0MEMOBJ;
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+
+ if (Mem.MapObjR3 != NIL_RTR0MEMOBJ)
+ {
+ int rc = RTR0MemObjFree(Mem.MapObjR3, false);
+ AssertRC(rc); /** @todo figure out how to handle this. */
+ }
+ if (Mem.MemObj != NIL_RTR0MEMOBJ)
+ {
+ int rc = RTR0MemObjFree(Mem.MemObj, true /* fFreeMappings */);
+ AssertRC(rc); /** @todo figure out how to handle this. */
+ }
+ return VINF_SUCCESS;
+ }
+ }
+ }
+ }
+ RTSpinlockRelease(pSession->Spinlock, &SpinlockTmp);
+ Log(("Failed to find %p!!! (eType=%d)\n", (void *)uPtr, eType));
+ return VERR_INVALID_PARAMETER;
+}
+
+
+/**
+ * Opens an image. If it's the first time it's opened the call must upload
+ * the bits using the supdrvIOCtl_LdrLoad() / SUPDRV_IOCTL_LDR_LOAD function.
+ *
+ * This is the 1st step of the loading.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pReq The open request.
+ */
+static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDROPEN pReq)
+{
+ PSUPDRVLDRIMAGE pImage;
+ unsigned cb;
+ void *pv;
+ LogFlow(("supdrvIOCtl_LdrOpen: szName=%s cbImage=%d\n", pReq->u.In.szName, pReq->u.In.cbImage));
+
+ /*
+ * Check if we got an instance of the image already.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+ for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
+ {
+ if (!strcmp(pImage->szName, pReq->u.In.szName))
+ {
+ pImage->cUsage++;
+ pReq->u.Out.pvImageBase = pImage->pvImage;
+ pReq->u.Out.fNeedsLoading = pImage->uState == SUP_IOCTL_LDR_OPEN;
+ supdrvLdrAddUsage(pSession, pImage);
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ return VINF_SUCCESS;
+ }
+ }
+ /* (not found - add it!) */
+
+ /*
+ * Allocate memory.
+ */
+ cb = pReq->u.In.cbImage + sizeof(SUPDRVLDRIMAGE) + 31;
+ pv = RTMemExecAlloc(cb);
+ if (!pv)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("supdrvIOCtl_LdrOpen: RTMemExecAlloc(%u) failed\n", cb));
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Setup and link in the LDR stuff.
+ */
+ pImage = (PSUPDRVLDRIMAGE)pv;
+ pImage->pvImage = RT_ALIGN_P(pImage + 1, 32);
+ pImage->cbImage = pReq->u.In.cbImage;
+ pImage->pfnModuleInit = NULL;
+ pImage->pfnModuleTerm = NULL;
+ pImage->pfnServiceReqHandler = NULL;
+ pImage->uState = SUP_IOCTL_LDR_OPEN;
+ pImage->cUsage = 1;
+ strcpy(pImage->szName, pReq->u.In.szName);
+
+ pImage->pNext = pDevExt->pLdrImages;
+ pDevExt->pLdrImages = pImage;
+
+ supdrvLdrAddUsage(pSession, pImage);
+
+ pReq->u.Out.pvImageBase = pImage->pvImage;
+ pReq->u.Out.fNeedsLoading = true;
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+
+#if defined(RT_OS_WINDOWS) && defined(DEBUG)
+ SUPR0Printf("VBoxDrv: windbg> .reload /f %s=%#p\n", pImage->szName, pImage->pvImage);
+#endif
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Loads the image bits.
+ *
+ * This is the 2nd step of the loading.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pReq The request.
+ */
+static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRLOAD pReq)
+{
+ PSUPDRVLDRUSAGE pUsage;
+ PSUPDRVLDRIMAGE pImage;
+ int rc;
+ LogFlow(("supdrvIOCtl_LdrLoad: pvImageBase=%p cbImage=%d\n", pReq->u.In.pvImageBase, pReq->u.In.cbImage));
+
+ /*
+ * Find the ldr image.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+ pUsage = pSession->pLdrUsage;
+ while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
+ pUsage = pUsage->pNext;
+ if (!pUsage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_LOAD: couldn't find image!\n"));
+ return VERR_INVALID_HANDLE;
+ }
+ pImage = pUsage->pImage;
+ if (pImage->cbImage != pReq->u.In.cbImage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_LOAD: image size mismatch!! %d(prep) != %d(load)\n", pImage->cbImage, pReq->u.In.cbImage));
+ return VERR_INVALID_HANDLE;
+ }
+ if (pImage->uState != SUP_IOCTL_LDR_OPEN)
+ {
+ unsigned uState = pImage->uState;
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ if (uState != SUP_IOCTL_LDR_LOAD)
+ AssertMsgFailed(("SUP_IOCTL_LDR_LOAD: invalid image state %d (%#x)!\n", uState, uState));
+ return SUPDRV_ERR_ALREADY_LOADED;
+ }
+ switch (pReq->u.In.eEPType)
+ {
+ case SUPLDRLOADEP_NOTHING:
+ break;
+
+ case SUPLDRLOADEP_VMMR0:
+ if ( !pReq->u.In.EP.VMMR0.pvVMMR0
+ || !pReq->u.In.EP.VMMR0.pvVMMR0EntryInt
+ || !pReq->u.In.EP.VMMR0.pvVMMR0EntryFast
+ || !pReq->u.In.EP.VMMR0.pvVMMR0EntryEx)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("NULL pointer: pvVMMR0=%p pvVMMR0EntryInt=%p pvVMMR0EntryFast=%p pvVMMR0EntryEx=%p!\n",
+ pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
+ pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx));
+ return VERR_INVALID_PARAMETER;
+ }
+ /** @todo validate pReq->u.In.EP.VMMR0.pvVMMR0 against pvImage! */
+ if ( (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryInt - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
+ || (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryFast - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage
+ || (uintptr_t)pReq->u.In.EP.VMMR0.pvVMMR0EntryEx - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("Out of range (%p LB %#x): pvVMMR0EntryInt=%p, pvVMMR0EntryFast=%p or pvVMMR0EntryEx=%p is NULL!\n",
+ pImage->pvImage, pReq->u.In.cbImage, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
+ pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx));
+ return VERR_INVALID_PARAMETER;
+ }
+ break;
+
+ case SUPLDRLOADEP_SERVICE:
+ if (!pReq->u.In.EP.Service.pfnServiceReq)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("NULL pointer: pfnServiceReq=%p!\n", pReq->u.In.EP.Service.pfnServiceReq));
+ return VERR_INVALID_PARAMETER;
+ }
+ if ((uintptr_t)pReq->u.In.EP.Service.pfnServiceReq - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("Out of range (%p LB %#x): pfnServiceReq=%p, pvVMMR0EntryFast=%p or pvVMMR0EntryEx=%p is NULL!\n",
+ pImage->pvImage, pReq->u.In.cbImage, pReq->u.In.EP.Service.pfnServiceReq));
+ return VERR_INVALID_PARAMETER;
+ }
+ if ( pReq->u.In.EP.Service.apvReserved[0] != NIL_RTR0PTR
+ || pReq->u.In.EP.Service.apvReserved[1] != NIL_RTR0PTR
+ || pReq->u.In.EP.Service.apvReserved[2] != NIL_RTR0PTR)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("Out of range (%p LB %#x): apvReserved={%p,%p,%p} MBZ!\n",
+ pImage->pvImage, pReq->u.In.cbImage,
+ pReq->u.In.EP.Service.apvReserved[0],
+ pReq->u.In.EP.Service.apvReserved[1],
+ pReq->u.In.EP.Service.apvReserved[2]));
+ return VERR_INVALID_PARAMETER;
+ }
+ break;
+
+ default:
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("Invalid eEPType=%d\n", pReq->u.In.eEPType));
+ return VERR_INVALID_PARAMETER;
+ }
+ if ( pReq->u.In.pfnModuleInit
+ && (uintptr_t)pReq->u.In.pfnModuleInit - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_LOAD: pfnModuleInit=%p is outside the image (%p %d bytes)\n",
+ pReq->u.In.pfnModuleInit, pImage->pvImage, pReq->u.In.cbImage));
+ return VERR_INVALID_PARAMETER;
+ }
+ if ( pReq->u.In.pfnModuleTerm
+ && (uintptr_t)pReq->u.In.pfnModuleTerm - (uintptr_t)pImage->pvImage >= pReq->u.In.cbImage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_LOAD: pfnModuleTerm=%p is outside the image (%p %d bytes)\n",
+ pReq->u.In.pfnModuleTerm, pImage->pvImage, pReq->u.In.cbImage));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Copy the memory.
+ */
+ /* no need to do try/except as this is a buffered request. */
+ memcpy(pImage->pvImage, &pReq->u.In.achImage[0], pImage->cbImage);
+ pImage->uState = SUP_IOCTL_LDR_LOAD;
+ pImage->pfnModuleInit = pReq->u.In.pfnModuleInit;
+ pImage->pfnModuleTerm = pReq->u.In.pfnModuleTerm;
+ pImage->offSymbols = pReq->u.In.offSymbols;
+ pImage->cSymbols = pReq->u.In.cSymbols;
+ pImage->offStrTab = pReq->u.In.offStrTab;
+ pImage->cbStrTab = pReq->u.In.cbStrTab;
+
+ /*
+ * Update any entry points.
+ */
+ switch (pReq->u.In.eEPType)
+ {
+ default:
+ case SUPLDRLOADEP_NOTHING:
+ rc = VINF_SUCCESS;
+ break;
+ case SUPLDRLOADEP_VMMR0:
+ rc = supdrvLdrSetVMMR0EPs(pDevExt, pReq->u.In.EP.VMMR0.pvVMMR0, pReq->u.In.EP.VMMR0.pvVMMR0EntryInt,
+ pReq->u.In.EP.VMMR0.pvVMMR0EntryFast, pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
+ break;
+ case SUPLDRLOADEP_SERVICE:
+ pImage->pfnServiceReqHandler = pReq->u.In.EP.Service.pfnServiceReq;
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ /*
+ * On success call the module initialization.
+ */
+ LogFlow(("supdrvIOCtl_LdrLoad: pfnModuleInit=%p\n", pImage->pfnModuleInit));
+ if (RT_SUCCESS(rc) && pImage->pfnModuleInit)
+ {
+ Log(("supdrvIOCtl_LdrLoad: calling pfnModuleInit=%p\n", pImage->pfnModuleInit));
+#ifdef RT_WITH_W64_UNWIND_HACK
+ rc = supdrvNtWrapModuleInit((PFNRT)pImage->pfnModuleInit);
+#else
+ rc = pImage->pfnModuleInit();
+#endif
+ if (rc && pDevExt->pvVMMR0 == pImage->pvImage)
+ supdrvLdrUnsetVMMR0EPs(pDevExt);
+ }
+
+ if (rc)
+ pImage->uState = SUP_IOCTL_LDR_OPEN;
+
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ return rc;
+}
+
+
+/**
+ * Frees a previously loaded (prep'ed) image.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pReq The request.
+ */
+static int supdrvIOCtl_LdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRFREE pReq)
+{
+ int rc;
+ PSUPDRVLDRUSAGE pUsagePrev;
+ PSUPDRVLDRUSAGE pUsage;
+ PSUPDRVLDRIMAGE pImage;
+ LogFlow(("supdrvIOCtl_LdrFree: pvImageBase=%p\n", pReq->u.In.pvImageBase));
+
+ /*
+ * Find the ldr image.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+ pUsagePrev = NULL;
+ pUsage = pSession->pLdrUsage;
+ while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
+ {
+ pUsagePrev = pUsage;
+ pUsage = pUsage->pNext;
+ }
+ if (!pUsage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_FREE: couldn't find image!\n"));
+ return VERR_INVALID_HANDLE;
+ }
+
+ /*
+ * Check if we can remove anything.
+ */
+ rc = VINF_SUCCESS;
+ pImage = pUsage->pImage;
+ if (pImage->cUsage <= 1 || pUsage->cUsage <= 1)
+ {
+ /*
+ * Check if there are any objects with destructors in the image, if
+ * so leave it for the session cleanup routine so we get a chance to
+ * clean things up in the right order and not leave them all dangling.
+ */
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+ if (pImage->cUsage <= 1)
+ {
+ PSUPDRVOBJ pObj;
+ for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
+ if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
+ {
+ rc = VERR_DANGLING_OBJECTS;
+ break;
+ }
+ }
+ else
+ {
+ PSUPDRVUSAGE pGenUsage;
+ for (pGenUsage = pSession->pUsage; pGenUsage; pGenUsage = pGenUsage->pNext)
+ if (RT_UNLIKELY((uintptr_t)pGenUsage->pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
+ {
+ rc = VERR_DANGLING_OBJECTS;
+ break;
+ }
+ }
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ if (rc == VINF_SUCCESS)
+ {
+ /* unlink it */
+ if (pUsagePrev)
+ pUsagePrev->pNext = pUsage->pNext;
+ else
+ pSession->pLdrUsage = pUsage->pNext;
+
+ /* free it */
+ pUsage->pImage = NULL;
+ pUsage->pNext = NULL;
+ RTMemFree(pUsage);
+
+ /*
+ * Derefrence the image.
+ */
+ if (pImage->cUsage <= 1)
+ supdrvLdrFree(pDevExt, pImage);
+ else
+ pImage->cUsage--;
+ }
+ else
+ {
+ Log(("supdrvIOCtl_LdrFree: Dangling objects in %p/%s!\n", pImage->pvImage, pImage->szName));
+ rc = VINF_SUCCESS; /** @todo BRANCH-2.1: remove this after branching. */
+ }
+ }
+ else
+ {
+ /*
+ * Dereference both image and usage.
+ */
+ pImage->cUsage--;
+ pUsage->cUsage--;
+ }
+
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ return rc;
+}
+
+
+/**
+ * Gets the address of a symbol in an open image.
+ *
+ * @returns 0 on success.
+ * @returns SUPDRV_ERR_* on failure.
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pReq The request buffer.
+ */
+static int supdrvIOCtl_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLDRGETSYMBOL pReq)
+{
+ PSUPDRVLDRIMAGE pImage;
+ PSUPDRVLDRUSAGE pUsage;
+ uint32_t i;
+ PSUPLDRSYM paSyms;
+ const char *pchStrings;
+ const size_t cbSymbol = strlen(pReq->u.In.szSymbol) + 1;
+ void *pvSymbol = NULL;
+ int rc = VERR_GENERAL_FAILURE;
+ Log3(("supdrvIOCtl_LdrGetSymbol: pvImageBase=%p szSymbol=\"%s\"\n", pReq->u.In.pvImageBase, pReq->u.In.szSymbol));
+
+ /*
+ * Find the ldr image.
+ */
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+ pUsage = pSession->pLdrUsage;
+ while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
+ pUsage = pUsage->pNext;
+ if (!pUsage)
+ {
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_GET_SYMBOL: couldn't find image!\n"));
+ return VERR_INVALID_HANDLE;
+ }
+ pImage = pUsage->pImage;
+ if (pImage->uState != SUP_IOCTL_LDR_LOAD)
+ {
+ unsigned uState = pImage->uState;
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ Log(("SUP_IOCTL_LDR_GET_SYMBOL: invalid image state %d (%#x)!\n", uState, uState)); NOREF(uState);
+ return VERR_ALREADY_LOADED;
+ }
+
+ /*
+ * Search the symbol strings.
+ */
+ pchStrings = (const char *)((uint8_t *)pImage->pvImage + pImage->offStrTab);
+ paSyms = (PSUPLDRSYM)((uint8_t *)pImage->pvImage + pImage->offSymbols);
+ for (i = 0; i < pImage->cSymbols; i++)
+ {
+ if ( paSyms[i].offSymbol < pImage->cbImage /* paranoia */
+ && paSyms[i].offName + cbSymbol <= pImage->cbStrTab
+ && !memcmp(pchStrings + paSyms[i].offName, pReq->u.In.szSymbol, cbSymbol))
+ {
+ pvSymbol = (uint8_t *)pImage->pvImage + paSyms[i].offSymbol;
+ rc = VINF_SUCCESS;
+ break;
+ }
+ }
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ pReq->u.Out.pvSymbol = pvSymbol;
+ return rc;
+}
+
+
+/**
+ * Gets the address of a symbol in an open image or the support driver.
+ *
+ * @returns VINF_SUCCESS on success.
+ * @returns
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pReq The request buffer.
+ */
+static int supdrvIDC_LdrGetSymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQGETSYM pReq)
+{
+ int rc = VINF_SUCCESS;
+ const char *pszSymbol = pReq->u.In.pszSymbol;
+ const char *pszModule = pReq->u.In.pszModule;
+ size_t cbSymbol;
+ char const *pszEnd;
+ uint32_t i;
+
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
+ pszEnd = (char *)memchr(pszSymbol, '\0', 512);
+ AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
+ cbSymbol = pszEnd - pszSymbol + 1;
+
+ if (pszModule)
+ {
+ AssertPtrReturn(pszModule, VERR_INVALID_POINTER);
+ pszEnd = (char *)memchr(pszModule, '\0', 64);
+ AssertReturn(pszEnd, VERR_INVALID_PARAMETER);
+ }
+ Log3(("supdrvIDC_LdrGetSymbol: pszModule=%p:{%s} pszSymbol=%p:{%s}\n", pszModule, pszModule, pszSymbol, pszSymbol));
+
+
+ if ( !pszModule
+ || !strcmp(pszModule, "SupDrv"))
+ {
+ /*
+ * Search the support driver export table.
+ */
+ for (i = 0; i < RT_ELEMENTS(g_aFunctions); i++)
+ if (!strcmp(g_aFunctions[i].szName, pszSymbol))
+ {
+ pReq->u.Out.pfnSymbol = g_aFunctions[i].pfn;
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Find the loader image.
+ */
+ PSUPDRVLDRIMAGE pImage;
+
+ RTSemFastMutexRequest(pDevExt->mtxLdr);
+
+ for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
+ if (!strcmp(pImage->szName, pszModule))
+ break;
+ if (pImage && pImage->uState == SUP_IOCTL_LDR_LOAD)
+ {
+ /*
+ * Search the symbol strings.
+ */
+ const char *pchStrings = (const char *)((uint8_t *)pImage->pvImage + pImage->offStrTab);
+ PCSUPLDRSYM paSyms = (PCSUPLDRSYM)((uint8_t *)pImage->pvImage + pImage->offSymbols);
+ for (i = 0; i < pImage->cSymbols; i++)
+ {
+ if ( paSyms[i].offSymbol < pImage->cbImage /* paranoia */
+ && paSyms[i].offName + cbSymbol <= pImage->cbStrTab
+ && !memcmp(pchStrings + paSyms[i].offName, pszSymbol, cbSymbol))
+ {
+ /*
+ * Found it! Calc the symbol address and add a reference to the module.
+ */
+ pReq->u.Out.pfnSymbol = (PFNRT)((uint8_t *)pImage->pvImage + paSyms[i].offSymbol);
+ rc = supdrvLdrAddUsage(pSession, pImage);
+ break;
+ }
+ }
+ }
+ else
+ rc = pImage ? VERR_WRONG_ORDER : VERR_MODULE_NOT_FOUND;
+
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+ }
+ return rc;
+}
+
+
+/**
+ * Updates the VMMR0 entry point pointers.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Device globals.
+ * @param pSession Session data.
+ * @param pVMMR0 VMMR0 image handle.
+ * @param pvVMMR0EntryInt VMMR0EntryInt address.
+ * @param pvVMMR0EntryFast VMMR0EntryFast address.
+ * @param pvVMMR0EntryEx VMMR0EntryEx address.
+ * @remark Caller must own the loader mutex.
+ */
+static int supdrvLdrSetVMMR0EPs(PSUPDRVDEVEXT pDevExt, void *pvVMMR0, void *pvVMMR0EntryInt, void *pvVMMR0EntryFast, void *pvVMMR0EntryEx)
+{
+ int rc = VINF_SUCCESS;
+ LogFlow(("supdrvLdrSetR0EP pvVMMR0=%p pvVMMR0EntryInt=%p\n", pvVMMR0, pvVMMR0EntryInt));
+
+
+ /*
+ * Check if not yet set.
+ */
+ if (!pDevExt->pvVMMR0)
+ {
+ pDevExt->pvVMMR0 = pvVMMR0;
+ pDevExt->pfnVMMR0EntryInt = pvVMMR0EntryInt;
+ pDevExt->pfnVMMR0EntryFast = pvVMMR0EntryFast;
+ pDevExt->pfnVMMR0EntryEx = pvVMMR0EntryEx;
+ }
+ else
+ {
+ /*
+ * Return failure or success depending on whether the values match or not.
+ */
+ if ( pDevExt->pvVMMR0 != pvVMMR0
+ || (void *)pDevExt->pfnVMMR0EntryInt != pvVMMR0EntryInt
+ || (void *)pDevExt->pfnVMMR0EntryFast != pvVMMR0EntryFast
+ || (void *)pDevExt->pfnVMMR0EntryEx != pvVMMR0EntryEx)
+ {
+ AssertMsgFailed(("SUP_IOCTL_LDR_SETR0EP: Already set pointing to a different module!\n"));
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * Unsets the VMMR0 entry point installed by supdrvLdrSetR0EP.
+ *
+ * @param pDevExt Device globals.
+ */
+static void supdrvLdrUnsetVMMR0EPs(PSUPDRVDEVEXT pDevExt)
+{
+ pDevExt->pvVMMR0 = NULL;
+ pDevExt->pfnVMMR0EntryInt = NULL;
+ pDevExt->pfnVMMR0EntryFast = NULL;
+ pDevExt->pfnVMMR0EntryEx = NULL;
+}
+
+
+/**
+ * Adds a usage reference in the specified session of an image.
+ *
+ * Called while owning the loader semaphore.
+ *
+ * @returns VINF_SUCCESS on success and VERR_NO_MEMORY on failure.
+ * @param pSession Session in question.
+ * @param pImage Image which the session is using.
+ */
+static int supdrvLdrAddUsage(PSUPDRVSESSION pSession, PSUPDRVLDRIMAGE pImage)
+{
+ PSUPDRVLDRUSAGE pUsage;
+ LogFlow(("supdrvLdrAddUsage: pImage=%p\n", pImage));
+
+ /*
+ * Referenced it already?
+ */
+ pUsage = pSession->pLdrUsage;
+ while (pUsage)
+ {
+ if (pUsage->pImage == pImage)
+ {
+ pUsage->cUsage++;
+ return VINF_SUCCESS;
+ }
+ pUsage = pUsage->pNext;
+ }
+
+ /*
+ * Allocate new usage record.
+ */
+ pUsage = (PSUPDRVLDRUSAGE)RTMemAlloc(sizeof(*pUsage));
+ AssertReturn(pUsage, VERR_NO_MEMORY);
+ pUsage->cUsage = 1;
+ pUsage->pImage = pImage;
+ pUsage->pNext = pSession->pLdrUsage;
+ pSession->pLdrUsage = pUsage;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Frees a load image.
+ *
+ * @param pDevExt Pointer to device extension.
+ * @param pImage Pointer to the image we're gonna free.
+ * This image must exit!
+ * @remark The caller MUST own SUPDRVDEVEXT::mtxLdr!
+ */
+static void supdrvLdrFree(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
+{
+ PSUPDRVLDRIMAGE pImagePrev;
+ LogFlow(("supdrvLdrFree: pImage=%p\n", pImage));
+
+ /* find it - arg. should've used doubly linked list. */
+ Assert(pDevExt->pLdrImages);
+ pImagePrev = NULL;
+ if (pDevExt->pLdrImages != pImage)
+ {
+ pImagePrev = pDevExt->pLdrImages;
+ while (pImagePrev->pNext != pImage)
+ pImagePrev = pImagePrev->pNext;
+ Assert(pImagePrev->pNext == pImage);
+ }
+
+ /* unlink */
+ if (pImagePrev)
+ pImagePrev->pNext = pImage->pNext;
+ else
+ pDevExt->pLdrImages = pImage->pNext;
+
+ /* check if this is VMMR0.r0 unset its entry point pointers. */
+ if (pDevExt->pvVMMR0 == pImage->pvImage)
+ supdrvLdrUnsetVMMR0EPs(pDevExt);
+
+ /* check for objects with destructors in this image. (Shouldn't happen.) */
+ if (pDevExt->pObjs)
+ {
+ unsigned cObjs = 0;
+ PSUPDRVOBJ pObj;
+ RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pDevExt->Spinlock, &SpinlockTmp);
+ for (pObj = pDevExt->pObjs; pObj; pObj = pObj->pNext)
+ if (RT_UNLIKELY((uintptr_t)pObj->pfnDestructor - (uintptr_t)pImage->pvImage < pImage->cbImage))
+ {
+ pObj->pfnDestructor = NULL;
+ cObjs++;
+ }
+ RTSpinlockRelease(pDevExt->Spinlock, &SpinlockTmp);
+ if (cObjs)
+ OSDBGPRINT(("supdrvLdrFree: Image '%s' has %d dangling objects!\n", pImage->szName, cObjs));
+ }
+
+ /* call termination function if fully loaded. */
+ if ( pImage->pfnModuleTerm
+ && pImage->uState == SUP_IOCTL_LDR_LOAD)
+ {
+ LogFlow(("supdrvIOCtl_LdrLoad: calling pfnModuleTerm=%p\n", pImage->pfnModuleTerm));
+#ifdef RT_WITH_W64_UNWIND_HACK
+ supdrvNtWrapModuleTerm(pImage->pfnModuleTerm);
+#else
+ pImage->pfnModuleTerm();
+#endif
+ }
+
+ /* free the image */
+ pImage->cUsage = 0;
+ pImage->pNext = 0;
+ pImage->uState = SUP_IOCTL_LDR_FREE;
+ RTMemExecFree(pImage);
+}
+
+
+/**
+ * Implements the service call request.
+ *
+ * @returns VBox status code.
+ * @param pDevExt The device extension.
+ * @param pSession The calling session.
+ * @param pReq The request packet, valid.
+ */
+static int supdrvIOCtl_CallServiceModule(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPCALLSERVICE pReq)
+{
+#if !defined(RT_OS_WINDOWS) || defined(DEBUG)
+ int rc;
+
+ /*
+ * Find the module first in the module referenced by the calling session.
+ */
+ rc = RTSemFastMutexRequest(pDevExt->mtxLdr);
+ if (RT_SUCCESS(rc))
+ {
+ PFNSUPR0SERVICEREQHANDLER pfnServiceReqHandler = NULL;
+ PSUPDRVLDRUSAGE pUsage;
+
+ for (pUsage = pSession->pLdrUsage; pUsage; pUsage = pUsage->pNext)
+ if ( pUsage->pImage->pfnServiceReqHandler
+ && !strcmp(pUsage->pImage->szName, pReq->u.In.szName))
+ {
+ pfnServiceReqHandler = pUsage->pImage->pfnServiceReqHandler;
+ break;
+ }
+ RTSemFastMutexRelease(pDevExt->mtxLdr);
+
+ if (pfnServiceReqHandler)
+ {
+ /*
+ * Call it.
+ */
+ if (pReq->Hdr.cbIn == SUP_IOCTL_CALL_SERVICE_SIZE(0))
+#ifdef RT_WITH_W64_UNWIND_HACK
+ rc = supdrvNtWrapServiceReqHandler((PFNRT)pfnServiceReqHandler, pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, NULL);
+#else
+ rc = pfnServiceReqHandler(pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, NULL);
+#endif
+ else
+#ifdef RT_WITH_W64_UNWIND_HACK
+ rc = supdrvNtWrapServiceReqHandler((PFNRT)pfnServiceReqHandler, pSession, pReq->u.In.uOperation,
+ pReq->u.In.u64Arg, (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0]);
+#else
+ rc = pfnServiceReqHandler(pSession, pReq->u.In.uOperation, pReq->u.In.u64Arg, (PSUPR0SERVICEREQHDR)&pReq->abReqPkt[0]);
+#endif
+ }
+ else
+ rc = VERR_SUPDRV_SERVICE_NOT_FOUND;
+ }
+
+ /* log it */
+ if ( RT_FAILURE(rc)
+ && rc != VERR_INTERRUPTED
+ && rc != VERR_TIMEOUT)
+ Log(("SUP_IOCTL_CALL_SERVICE: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+ else
+ Log4(("SUP_IOCTL_CALL_SERVICE: rc=%Rrc op=%u out=%u arg=%RX64 p/t=%RTproc/%RTthrd\n",
+ rc, pReq->u.In.uOperation, pReq->Hdr.cbOut, pReq->u.In.u64Arg, RTProcSelf(), RTThreadNativeSelf()));
+ return rc;
+#else /* RT_OS_WINDOWS && !DEBUG */
+ return VERR_NOT_IMPLEMENTED;
+#endif /* RT_OS_WINDOWS && !DEBUG */
+}
+
+
+/**
+ * Gets the paging mode of the current CPU.
+ *
+ * @returns Paging mode, SUPPAGEINGMODE_INVALID on error.
+ */
+SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void)
+{
+ SUPPAGINGMODE enmMode;
+
+ RTR0UINTREG cr0 = ASMGetCR0();
+ if ((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE))
+ enmMode = SUPPAGINGMODE_INVALID;
+ else
+ {
+ RTR0UINTREG cr4 = ASMGetCR4();
+ uint32_t fNXEPlusLMA = 0;
+ if (cr4 & X86_CR4_PAE)
+ {
+ uint32_t fAmdFeatures = ASMCpuId_EDX(0x80000001);
+ if (fAmdFeatures & (X86_CPUID_AMD_FEATURE_EDX_NX | X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
+ {
+ uint64_t efer = ASMRdMsr(MSR_K6_EFER);
+ if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_NX) && (efer & MSR_K6_EFER_NXE))
+ fNXEPlusLMA |= RT_BIT(0);
+ if ((fAmdFeatures & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE) && (efer & MSR_K6_EFER_LMA))
+ fNXEPlusLMA |= RT_BIT(1);
+ }
+ }
+
+ switch ((cr4 & (X86_CR4_PAE | X86_CR4_PGE)) | fNXEPlusLMA)
+ {
+ case 0:
+ enmMode = SUPPAGINGMODE_32_BIT;
+ break;
+
+ case X86_CR4_PGE:
+ enmMode = SUPPAGINGMODE_32_BIT_GLOBAL;
+ break;
+
+ case X86_CR4_PAE:
+ enmMode = SUPPAGINGMODE_PAE;
+ break;
+
+ case X86_CR4_PAE | RT_BIT(0):
+ enmMode = SUPPAGINGMODE_PAE_NX;
+ break;
+
+ case X86_CR4_PAE | X86_CR4_PGE:
+ enmMode = SUPPAGINGMODE_PAE_GLOBAL;
+ break;
+
+ case X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
+ enmMode = SUPPAGINGMODE_PAE_GLOBAL;
+ break;
+
+ case RT_BIT(1) | X86_CR4_PAE:
+ enmMode = SUPPAGINGMODE_AMD64;
+ break;
+
+ case RT_BIT(1) | X86_CR4_PAE | RT_BIT(0):
+ enmMode = SUPPAGINGMODE_AMD64_NX;
+ break;
+
+ case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE:
+ enmMode = SUPPAGINGMODE_AMD64_GLOBAL;
+ break;
+
+ case RT_BIT(1) | X86_CR4_PAE | X86_CR4_PGE | RT_BIT(0):
+ enmMode = SUPPAGINGMODE_AMD64_GLOBAL_NX;
+ break;
+
+ default:
+ AssertMsgFailed(("Cannot happen! cr4=%#x fNXEPlusLMA=%d\n", cr4, fNXEPlusLMA));
+ enmMode = SUPPAGINGMODE_INVALID;
+ break;
+ }
+ }
+ return enmMode;
+}
+
+
+/**
+ * Enables or disabled hardware virtualization extensions using native OS APIs.
+ *
+ * @returns VBox status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_NOT_SUPPORTED if not supported by the native OS.
+ *
+ * @param fEnable Whether to enable or disable.
+ */
+SUPR0DECL(int) SUPR0EnableVTx(bool fEnable)
+{
+#ifdef RT_OS_DARWIN
+ return supdrvOSEnableVTx(fEnable);
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+/**
+ * Creates the GIP.
+ *
+ * @returns VBox status code.
+ * @param pDevExt Instance data. GIP stuff may be updated.
+ */
+static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt)
+{
+ PSUPGLOBALINFOPAGE pGip;
+ RTHCPHYS HCPhysGip;
+ uint32_t u32SystemResolution;
+ uint32_t u32Interval;
+ int rc;
+
+ LogFlow(("supdrvGipCreate:\n"));
+
+ /* assert order */
+ Assert(pDevExt->u32SystemTimerGranularityGrant == 0);
+ Assert(pDevExt->GipMemObj == NIL_RTR0MEMOBJ);
+ Assert(!pDevExt->pGipTimer);
+
+ /*
+ * Allocate a suitable page with a default kernel mapping.
+ */
+ rc = RTR0MemObjAllocLow(&pDevExt->GipMemObj, PAGE_SIZE, false);
+ if (RT_FAILURE(rc))
+ {
+ OSDBGPRINT(("supdrvGipCreate: failed to allocate the GIP page. rc=%d\n", rc));
+ return rc;
+ }
+ pGip = (PSUPGLOBALINFOPAGE)RTR0MemObjAddress(pDevExt->GipMemObj); AssertPtr(pGip);
+ HCPhysGip = RTR0MemObjGetPagePhysAddr(pDevExt->GipMemObj, 0); Assert(HCPhysGip != NIL_RTHCPHYS);
+
+#if 0 /** @todo Disabled this as we didn't used to do it before and causes unnecessary stress on laptops.
+ * It only applies to Windows and should probably revisited later, if possible made part of the
+ * timer code (return min granularity in RTTimerGetSystemGranularity and set it in RTTimerStart). */
+ /*
+ * Try bump up the system timer resolution.
+ * The more interrupts the better...
+ */
+ if ( RT_SUCCESS(RTTimerRequestSystemGranularity( 488281 /* 2048 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 500000 /* 2000 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 976563 /* 1024 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 1953125 /* 512 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 2000000 /* 500 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 3906250 /* 256 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 4000000 /* 250 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity( 7812500 /* 128 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity(10000000 /* 100 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity(15625000 /* 64 HZ */, &u32SystemResolution))
+ || RT_SUCCESS(RTTimerRequestSystemGranularity(31250000 /* 32 HZ */, &u32SystemResolution))
+ )
+ {
+ Assert(RTTimerGetSystemGranularity() <= u32SystemResolution);
+ pDevExt->u32SystemTimerGranularityGrant = u32SystemResolution;
+ }
+#endif
+
+ /*
+ * Find a reasonable update interval and initialize the structure.
+ */
+ u32Interval = u32SystemResolution = RTTimerGetSystemGranularity();
+ while (u32Interval < 10000000 /* 10 ms */)
+ u32Interval += u32SystemResolution;
+
+ supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), 1000000000 / u32Interval /*=Hz*/);
+
+ /*
+ * Create the timer.
+ * If CPU_ALL isn't supported we'll have to fall back to synchronous mode.
+ */
+ if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
+ {
+ rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n"));
+ pGip->u32Mode = SUPGIPMODE_SYNC_TSC;
+ }
+ }
+ if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
+ rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0, supdrvGipSyncTimer, pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
+ rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * We're good.
+ */
+ dprintf(("supdrvGipCreate: %ld ns interval.\n", (long)u32Interval));
+ return VINF_SUCCESS;
+ }
+
+ OSDBGPRINT(("supdrvGipCreate: failed register MP event notfication. rc=%d\n", rc));
+ }
+ else
+ {
+ OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %ld ns interval. rc=%d\n", (long)u32Interval, rc));
+ Assert(!pDevExt->pGipTimer);
+ }
+ supdrvGipDestroy(pDevExt);
+ return rc;
+}
+
+
+/**
+ * Terminates the GIP.
+ *
+ * @param pDevExt Instance data. GIP stuff may be updated.
+ */
+static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt)
+{
+ int rc;
+#ifdef DEBUG_DARWIN_GIP
+ OSDBGPRINT(("supdrvGipDestroy: pDevExt=%p pGip=%p pGipTimer=%p GipMemObj=%p\n", pDevExt,
+ pDevExt->GipMemObj != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pDevExt->GipMemObj) : NULL,
+ pDevExt->pGipTimer, pDevExt->GipMemObj));
+#endif
+
+ /*
+ * Invalid the GIP data.
+ */
+ if (pDevExt->pGip)
+ {
+ supdrvGipTerm(pDevExt->pGip);
+ pDevExt->pGip = NULL;
+ }
+
+ /*
+ * Destroy the timer and free the GIP memory object.
+ */
+ if (pDevExt->pGipTimer)
+ {
+ rc = RTTimerDestroy(pDevExt->pGipTimer); AssertRC(rc);
+ pDevExt->pGipTimer = NULL;
+ }
+
+ if (pDevExt->GipMemObj != NIL_RTR0MEMOBJ)
+ {
+ rc = RTR0MemObjFree(pDevExt->GipMemObj, true /* free mappings */); AssertRC(rc);
+ pDevExt->GipMemObj = NIL_RTR0MEMOBJ;
+ }
+
+ /*
+ * Finally, release the system timer resolution request if one succeeded.
+ */
+ if (pDevExt->u32SystemTimerGranularityGrant)
+ {
+ rc = RTTimerReleaseSystemGranularity(pDevExt->u32SystemTimerGranularityGrant); AssertRC(rc);
+ pDevExt->u32SystemTimerGranularityGrant = 0;
+ }
+}
+
+
+/**
+ * Timer callback function sync GIP mode.
+ * @param pTimer The timer.
+ * @param pvUser The device extension.
+ */
+static DECLCALLBACK(void) supdrvGipSyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+ RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
+
+ supdrvGipUpdate(pDevExt->pGip, RTTimeSystemNanoTS());
+
+ ASMSetFlags(fOldFlags);
+}
+
+
+/**
+ * Timer callback function for async GIP mode.
+ * @param pTimer The timer.
+ * @param pvUser The device extension.
+ */
+static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+ RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
+ RTCPUID idCpu = RTMpCpuId();
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+
+ /** @todo reset the transaction number and whatnot when iTick == 1. */
+ if (pDevExt->idGipMaster == idCpu)
+ supdrvGipUpdate(pDevExt->pGip, NanoTS);
+ else
+ supdrvGipUpdatePerCpu(pDevExt->pGip, NanoTS, ASMGetApicId());
+
+ ASMSetFlags(fOldFlags);
+}
+
+
+/**
+ * Multiprocessor event notification callback.
+ *
+ * This is used to make sue that the GIP master gets passed on to
+ * another CPU.
+ *
+ * @param enmEvent The event.
+ * @param idCpu The cpu it applies to.
+ * @param pvUser Pointer to the device extension.
+ */
+static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
+{
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
+ if (enmEvent == RTMPEVENT_OFFLINE)
+ {
+ RTCPUID idGipMaster;
+ ASMAtomicReadSize(&pDevExt->idGipMaster, &idGipMaster);
+ if (idGipMaster == idCpu)
+ {
+ /*
+ * Find a new GIP master.
+ */
+ bool fIgnored;
+ unsigned i;
+ RTCPUID idNewGipMaster = NIL_RTCPUID;
+ RTCPUSET OnlineCpus;
+ RTMpGetOnlineSet(&OnlineCpus);
+
+ for (i = 0; i < RTCPUSET_MAX_CPUS; i++)
+ {
+ RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
+ if ( RTCpuSetIsMember(&OnlineCpus, idCurCpu)
+ && idCurCpu != idGipMaster)
+ {
+ idNewGipMaster = idCurCpu;
+ break;
+ }
+ }
+
+ dprintf(("supdrvGipMpEvent: Gip master %#lx -> %#lx\n", (long)idGipMaster, (long)idNewGipMaster));
+ ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored);
+ NOREF(fIgnored);
+ }
+ }
+}
+
+
+/**
+ * Initializes the GIP data.
+ *
+ * @returns IPRT status code.
+ * @param pDevExt Pointer to the device instance data.
+ * @param pGip Pointer to the read-write kernel mapping of the GIP.
+ * @param HCPhys The physical address of the GIP.
+ * @param u64NanoTS The current nanosecond timestamp.
+ * @param uUpdateHz The update freqence.
+ */
+int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz)
+{
+ unsigned i;
+#ifdef DEBUG_DARWIN_GIP
+ OSDBGPRINT(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
+#else
+ LogFlow(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz));
+#endif
+
+ /*
+ * Initialize the structure.
+ */
+ memset(pGip, 0, PAGE_SIZE);
+ pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
+ pGip->u32Version = SUPGLOBALINFOPAGE_VERSION;
+ pGip->u32Mode = supdrvGipDeterminTscMode(pDevExt);
+ pGip->u32UpdateHz = uUpdateHz;
+ pGip->u32UpdateIntervalNS = 1000000000 / uUpdateHz;
+ pGip->u64NanoTSLastUpdateHz = u64NanoTS;
+
+ for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
+ {
+ pGip->aCPUs[i].u32TransactionId = 2;
+ pGip->aCPUs[i].u64NanoTS = u64NanoTS;
+ pGip->aCPUs[i].u64TSC = ASMReadTSC();
+
+ /*
+ * We don't know the following values until we've executed updates.
+ * So, we'll just insert very high values.
+ */
+ pGip->aCPUs[i].u64CpuHz = _4G + 1;
+ pGip->aCPUs[i].u32UpdateIntervalTSC = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[0] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[1] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[2] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[3] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[4] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[5] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[6] = _2G / 4;
+ pGip->aCPUs[i].au32TSCHistory[7] = _2G / 4;
+ }
+
+ /*
+ * Link it to the device extension.
+ */
+ pDevExt->pGip = pGip;
+ pDevExt->HCPhysGip = HCPhys;
+ pDevExt->cGipUsers = 0;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Callback used by supdrvDetermineAsyncTSC to read the TSC on a CPU.
+ *
+ * @param idCpu Ignored.
+ * @param pvUser1 Where to put the TSC.
+ * @param pvUser2 Ignored.
+ */
+static DECLCALLBACK(void) supdrvDetermineAsyncTscWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+#if 1
+ ASMAtomicWriteU64((uint64_t volatile *)pvUser1, ASMReadTSC());
+#else
+ *(uint64_t *)pvUser1 = ASMReadTSC();
+#endif
+}
+
+
+/**
+ * Determine if Async GIP mode is required because of TSC drift.
+ *
+ * When using the default/normal timer code it is essential that the time stamp counter
+ * (TSC) runs never backwards, that is, a read operation to the counter should return
+ * a bigger value than any previous read operation. This is guaranteed by the latest
+ * AMD CPUs and by newer Intel CPUs which never enter the C2 state (P4). In any other
+ * case we have to choose the asynchronous timer mode.
+ *
+ * @param poffMin Pointer to the determined difference between different cores.
+ * @return false if the time stamp counters appear to be synchron, true otherwise.
+ */
+bool VBOXCALL supdrvDetermineAsyncTsc(uint64_t *poffMin)
+{
+ /*
+ * Just iterate all the cpus 8 times and make sure that the TSC is
+ * ever increasing. We don't bother taking TSC rollover into account.
+ */
+ RTCPUSET CpuSet;
+ int iLastCpu = RTCpuLastIndex(RTMpGetSet(&CpuSet));
+ int iCpu;
+ int cLoops = 8;
+ bool fAsync = false;
+ int rc = VINF_SUCCESS;
+ uint64_t offMax = 0;
+ uint64_t offMin = ~(uint64_t)0;
+ uint64_t PrevTsc = ASMReadTSC();
+
+ while (cLoops-- > 0)
+ {
+ for (iCpu = 0; iCpu <= iLastCpu; iCpu++)
+ {
+ uint64_t CurTsc;
+ rc = RTMpOnSpecific(RTMpCpuIdFromSetIndex(iCpu), supdrvDetermineAsyncTscWorker, &CurTsc, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ if (CurTsc <= PrevTsc)
+ {
+ fAsync = true;
+ offMin = offMax = PrevTsc - CurTsc;
+ dprintf(("supdrvDetermineAsyncTsc: iCpu=%d cLoops=%d CurTsc=%llx PrevTsc=%llx\n",
+ iCpu, cLoops, CurTsc, PrevTsc));
+ break;
+ }
+
+ /* Gather statistics (except the first time). */
+ if (iCpu != 0 || cLoops != 7)
+ {
+ uint64_t off = CurTsc - PrevTsc;
+ if (off < offMin)
+ offMin = off;
+ if (off > offMax)
+ offMax = off;
+ dprintf2(("%d/%d: off=%llx\n", cLoops, iCpu, off));
+ }
+
+ /* Next */
+ PrevTsc = CurTsc;
+ }
+ else if (rc == VERR_NOT_SUPPORTED)
+ break;
+ else
+ AssertMsg(rc == VERR_CPU_NOT_FOUND || rc == VERR_CPU_OFFLINE, ("%d\n", rc));
+ }
+
+ /* broke out of the loop. */
+ if (iCpu <= iLastCpu)
+ break;
+ }
+
+ *poffMin = offMin; /* Almost RTMpOnSpecific profiling. */
+ dprintf(("supdrvDetermineAsyncTsc: returns %d; iLastCpu=%d rc=%d offMin=%llx offMax=%llx\n",
+ fAsync, iLastCpu, rc, offMin, offMax));
+#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
+ OSDBGPRINT(("vboxdrv: fAsync=%d offMin=%#lx offMax=%#lx\n", fAsync, (long)offMin, (long)offMax));
+#endif
+ return fAsync;
+}
+
+
+/**
+ * Determin the GIP TSC mode.
+ *
+ * @returns The most suitable TSC mode.
+ * @param pDevExt Pointer to the device instance data.
+ */
+static SUPGIPMODE supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ /*
+ * On SMP we're faced with two problems:
+ * (1) There might be a skew between the CPU, so that cpu0
+ * returns a TSC that is sligtly different from cpu1.
+ * (2) Power management (and other things) may cause the TSC
+ * to run at a non-constant speed, and cause the speed
+ * to be different on the cpus. This will result in (1).
+ *
+ * So, on SMP systems we'll have to select the ASYNC update method
+ * if there are symphoms of these problems.
+ */
+ if (RTMpGetCount() > 1)
+ {
+ uint32_t uEAX, uEBX, uECX, uEDX;
+ uint64_t u64DiffCoresIgnored;
+
+ /* Permit the user and/or the OS specfic bits to force async mode. */
+ if (supdrvOSGetForcedAsyncTscMode(pDevExt))
+ return SUPGIPMODE_ASYNC_TSC;
+
+ /* Try check for current differences between the cpus. */
+ if (supdrvDetermineAsyncTsc(&u64DiffCoresIgnored))
+ return SUPGIPMODE_ASYNC_TSC;
+
+ /*
+ * If the CPU supports power management and is an AMD one we
+ * won't trust it unless it has the TscInvariant bit is set.
+ */
+ /* Check for "AuthenticAMD" */
+ ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
+ if ( uEAX >= 1
+ && uEBX == X86_CPUID_VENDOR_AMD_EBX
+ && uECX == X86_CPUID_VENDOR_AMD_ECX
+ && uEDX == X86_CPUID_VENDOR_AMD_EDX)
+ {
+ /* Check for APM support and that TscInvariant is cleared. */
+ ASMCpuId(0x80000000, &uEAX, &uEBX, &uECX, &uEDX);
+ if (uEAX >= 0x80000007)
+ {
+ ASMCpuId(0x80000007, &uEAX, &uEBX, &uECX, &uEDX);
+ if ( !(uEDX & RT_BIT(8))/* TscInvariant */
+ && (uEDX & 0x3e)) /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
+ return SUPGIPMODE_ASYNC_TSC;
+ }
+ }
+ }
+ return SUPGIPMODE_SYNC_TSC;
+}
+
+
+/**
+ * Invalidates the GIP data upon termination.
+ *
+ * @param pGip Pointer to the read-write kernel mapping of the GIP.
+ */
+void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip)
+{
+ unsigned i;
+ pGip->u32Magic = 0;
+ for (i = 0; i < RT_ELEMENTS(pGip->aCPUs); i++)
+ {
+ pGip->aCPUs[i].u64NanoTS = 0;
+ pGip->aCPUs[i].u64TSC = 0;
+ pGip->aCPUs[i].iTSCHistoryHead = 0;
+ }
+}
+
+
+/**
+ * Worker routine for supdrvGipUpdate and supdrvGipUpdatePerCpu that
+ * updates all the per cpu data except the transaction id.
+ *
+ * @param pGip The GIP.
+ * @param pGipCpu Pointer to the per cpu data.
+ * @param u64NanoTS The current time stamp.
+ */
+static void supdrvGipDoUpdateCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
+{
+ uint64_t u64TSC;
+ uint64_t u64TSCDelta;
+ uint32_t u32UpdateIntervalTSC;
+ uint32_t u32UpdateIntervalTSCSlack;
+ unsigned iTSCHistoryHead;
+ uint64_t u64CpuHz;
+
+ /*
+ * Update the NanoTS.
+ */
+ ASMAtomicXchgU64(&pGipCpu->u64NanoTS, u64NanoTS);
+
+ /*
+ * Calc TSC delta.
+ */
+ /** @todo validate the NanoTS delta, don't trust the OS to call us when it should... */
+ u64TSC = ASMReadTSC();
+ u64TSCDelta = u64TSC - pGipCpu->u64TSC;
+ ASMAtomicXchgU64(&pGipCpu->u64TSC, u64TSC);
+
+ if (u64TSCDelta >> 32)
+ {
+ u64TSCDelta = pGipCpu->u32UpdateIntervalTSC;
+ pGipCpu->cErrors++;
+ }
+
+ /*
+ * TSC History.
+ */
+ Assert(RT_ELEMENTS(pGipCpu->au32TSCHistory) == 8);
+
+ iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7;
+ ASMAtomicXchgU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead);
+ ASMAtomicXchgU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
+
+ /*
+ * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
+ */
+ if (pGip->u32UpdateHz >= 1000)
+ {
+ uint32_t u32;
+ u32 = pGipCpu->au32TSCHistory[0];
+ u32 += pGipCpu->au32TSCHistory[1];
+ u32 += pGipCpu->au32TSCHistory[2];
+ u32 += pGipCpu->au32TSCHistory[3];
+ u32 >>= 2;
+ u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4];
+ u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5];
+ u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6];
+ u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7];
+ u32UpdateIntervalTSC >>= 2;
+ u32UpdateIntervalTSC += u32;
+ u32UpdateIntervalTSC >>= 1;
+
+ /* Value choosen for a 2GHz Athlon64 running linux 2.6.10/11, . */
+ u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
+ }
+ else if (pGip->u32UpdateHz >= 90)
+ {
+ u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
+ u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
+ u32UpdateIntervalTSC >>= 1;
+
+ /* value choosen on a 2GHz thinkpad running windows */
+ u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
+ }
+ else
+ {
+ u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
+
+ /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
+ u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
+ }
+ ASMAtomicXchgU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
+
+ /*
+ * CpuHz.
+ */
+ u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
+ ASMAtomicXchgU64(&pGipCpu->u64CpuHz, u64CpuHz);
+}
+
+
+/**
+ * Updates the GIP.
+ *
+ * @param pGip Pointer to the GIP.
+ * @param u64NanoTS The current nanosecond timesamp.
+ */
+void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS)
+{
+ /*
+ * Determin the relevant CPU data.
+ */
+ PSUPGIPCPU pGipCpu;
+ if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
+ pGipCpu = &pGip->aCPUs[0];
+ else
+ {
+ unsigned iCpu = ASMGetApicId();
+ if (RT_LIKELY(iCpu >= RT_ELEMENTS(pGip->aCPUs)))
+ return;
+ pGipCpu = &pGip->aCPUs[iCpu];
+ }
+
+ /*
+ * Start update transaction.
+ */
+ if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
+ {
+ /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
+ AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
+ ASMAtomicIncU32(&pGipCpu->u32TransactionId);
+ pGipCpu->cErrors++;
+ return;
+ }
+
+ /*
+ * Recalc the update frequency every 0x800th time.
+ */
+ if (!(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
+ {
+ if (pGip->u64NanoTSLastUpdateHz)
+ {
+#ifdef RT_ARCH_AMD64 /** @todo fix 64-bit div here to work on x86 linux. */
+ uint64_t u64Delta = u64NanoTS - pGip->u64NanoTSLastUpdateHz;
+ uint32_t u32UpdateHz = (uint32_t)((UINT64_C(1000000000) * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
+ if (u32UpdateHz <= 2000 && u32UpdateHz >= 30)
+ {
+ ASMAtomicXchgU32(&pGip->u32UpdateHz, u32UpdateHz);
+ ASMAtomicXchgU32(&pGip->u32UpdateIntervalNS, 1000000000 / u32UpdateHz);
+ }
+#endif
+ }
+ ASMAtomicXchgU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS);
+ }
+
+ /*
+ * Update the data.
+ */
+ supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
+
+ /*
+ * Complete transaction.
+ */
+ ASMAtomicIncU32(&pGipCpu->u32TransactionId);
+}
+
+
+/**
+ * Updates the per cpu GIP data for the calling cpu.
+ *
+ * @param pGip Pointer to the GIP.
+ * @param u64NanoTS The current nanosecond timesamp.
+ * @param iCpu The CPU index.
+ */
+void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu)
+{
+ PSUPGIPCPU pGipCpu;
+
+ if (RT_LIKELY(iCpu < RT_ELEMENTS(pGip->aCPUs)))
+ {
+ pGipCpu = &pGip->aCPUs[iCpu];
+
+ /*
+ * Start update transaction.
+ */
+ if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
+ {
+ AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
+ ASMAtomicIncU32(&pGipCpu->u32TransactionId);
+ pGipCpu->cErrors++;
+ return;
+ }
+
+ /*
+ * Update the data.
+ */
+ supdrvGipDoUpdateCpu(pGip, pGipCpu, u64NanoTS);
+
+ /*
+ * Complete transaction.
+ */
+ ASMAtomicIncU32(&pGipCpu->u32TransactionId);
+ }
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIDC.h b/src/VBox/HostDrivers/Support/SUPDrvIDC.h
new file mode 100644
index 000000000..785dc66ac
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPDrvIDC.h
@@ -0,0 +1,276 @@
+/* $Id: SUPDrvIDC.h 10377 2008-07-08 16:26:13Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - Inter-Driver Communciation (IDC) definitions.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPDrvIDC_h___
+#define ___SUPDrvIDC_h___
+
+#include <VBox/types.h>
+
+/** @def SUP_IDC_CODE
+ * Creates IDC function code.
+ *
+ * @param Function The function number to encode, 1..255.
+ *
+ * @remarks We can take a sligtly more relaxed attitude wrt to size encoding
+ * here since only windows will use standard I/O control function code.
+ */
+#ifdef RT_OS_WINDOWS
+# define SUP_IDC_CODE(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) + 2542, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#else
+# define SUP_IDC_CODE(Function) ( UINT32_C(0xc0ffee00) | (uint32_t)(0x000000ff & (Function)) )
+#endif
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+#ifdef RT_ARCH_AMD64
+# pragma pack(8) /* paranoia. */
+#else
+# pragma pack(4) /* paranoia. */
+#endif
+
+
+/**
+ * An IDC request packet header.
+ *
+ * The main purpose of this header is to pass the session handle
+ * and status code in a generic manner in order to make things
+ * easier on the receiving end.
+ */
+typedef struct SUPDRVIDCREQHDR
+{
+ /** IN: The size of the request. */
+ uint32_t cb;
+ /** OUT: Status code of the request. */
+ int32_t rc;
+ /** IN: Pointer to the session handle. */
+ PSUPDRVSESSION pSession;
+#if ARCH_BITS == 32
+ /** Padding the structure to 16-bytes. */
+ uint32_t u32Padding;
+#endif
+} SUPDRVIDCREQHDR;
+/** Pointer to an IDC request packet header. */
+typedef SUPDRVIDCREQHDR *PSUPDRVIDCREQHDR;
+/** Pointer to a const IDC request packet header. */
+typedef SUPDRVIDCREQHDR const *PCSUPDRVIDCREQHDR;
+
+
+/**
+ * SUPDRV IDC: Connect request.
+ * This request takes a SUPDRVIDCREQCONNECT packet.
+ */
+#define SUPDRV_IDC_REQ_CONNECT SUP_IDC_CODE(1)
+/** A SUPDRV IDC connect request packet. */
+typedef struct SUPDRVIDCREQCONNECT
+{
+ /** The request header. */
+ SUPDRVIDCREQHDR Hdr;
+ /** The payload union. */
+ union
+ {
+ /** The input. */
+ struct SUPDRVIDCREQCONNECTIN
+ {
+ /** The magic cookie (SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE). */
+ uint32_t u32MagicCookie;
+ /** The desired version of the IDC interface. */
+ uint32_t uReqVersion;
+ /** The minimum version of the IDC interface. */
+ uint32_t uMinVersion;
+ } In;
+
+ /** The output. */
+ struct SUPDRVIDCREQCONNECTOUT
+ {
+ /** The support driver session. (An opaque.) */
+ PSUPDRVSESSION pSession;
+ /** The version of the IDC interface for this session. */
+ uint32_t uSessionVersion;
+ /** The version of the IDC interface . */
+ uint32_t uDriverVersion;
+ /** The SVN revision of the driver.
+ * This will be set to 0 if not compiled into the driver. */
+ uint32_t uDriverRevision;
+ } Out;
+ } u;
+} SUPDRVIDCREQCONNECT;
+/** Pointer to a SUPDRV IDC connect request. */
+typedef SUPDRVIDCREQCONNECT *PSUPDRVIDCREQCONNECT;
+/** Magic cookie value (SUPDRVIDCREQCONNECT::In.u32MagicCookie). ('tori') */
+#define SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE UINT32_C(0x69726f74)
+
+
+/**
+ * SUPDRV IDC: Disconnect request.
+ * This request only requires a SUPDRVIDCREQHDR.
+ */
+#define SUPDRV_IDC_REQ_DISCONNECT SUP_IDC_CODE(2)
+
+
+/**
+ * SUPDRV IDC: Query a symbol address.
+ * This request takes a SUPDRVIDCREQGETSYM packet.
+ */
+#define SUPDRV_IDC_REQ_GET_SYMBOL SUP_IDC_CODE(3)
+/** A SUPDRV IDC get symbol request packet. */
+typedef struct SUPDRVIDCREQGETSYM
+{
+ /** The request header. */
+ SUPDRVIDCREQHDR Hdr;
+ /** The payload union. */
+ union
+ {
+ /** The input. */
+ struct SUPDRVIDCREQGETSYMIN
+ {
+ /** The module name.
+ * NULL is an alias for the support driver. */
+ const char *pszModule;
+ /** The symbol name. */
+ const char *pszSymbol;
+ } In;
+
+ /** The output. */
+ struct SUPDRVIDCREQGETSYMOUT
+ {
+ /** The symbol address. */
+ PFNRT pfnSymbol;
+ } Out;
+ } u;
+} SUPDRVIDCREQGETSYM;
+/** Pointer to a SUPDRV IDC get symbol request. */
+typedef SUPDRVIDCREQGETSYM *PSUPDRVIDCREQGETSYM;
+
+
+/**
+ * SUPDRV IDC: Request the registration of a component factory.
+ * This request takes a SUPDRVIDCREQCOMPREGFACTORY packet.
+ */
+#define SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY SUP_IDC_CODE(10)
+/** A SUPDRV IDC register component factory request packet. */
+typedef struct SUPDRVIDCREQCOMPREGFACTORY
+{
+ /** The request header. */
+ SUPDRVIDCREQHDR Hdr;
+ /** The payload union. */
+ union
+ {
+ /** The input. */
+ struct SUPDRVIDCREQCOMPREGFACTORYIN
+ {
+ /** Pointer to the factory. */
+ PCSUPDRVFACTORY pFactory;
+ } In;
+ } u;
+} SUPDRVIDCREQCOMPREGFACTORY;
+/** Pointer to a SUPDRV IDC register component factory request. */
+typedef SUPDRVIDCREQCOMPREGFACTORY *PSUPDRVIDCREQCOMPREGFACTORY;
+
+
+/**
+ * SUPDRV IDC: Dergister a component factory.
+ * This request takes a SUPDRVIDCREQCOMPDEREGFACTORY packet.
+ */
+#define SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY SUP_IDC_CODE(11)
+/** A SUPDRV IDC deregister component factory request packet. */
+typedef struct SUPDRVIDCREQCOMPDEREGFACTORY
+{
+ /** The request header. */
+ SUPDRVIDCREQHDR Hdr;
+ /** The payload union. */
+ union
+ {
+ /** The input. */
+ struct SUPDRVIDCREQCOMPDEREGFACTORYIN
+ {
+ /** Pointer to the factory. */
+ PCSUPDRVFACTORY pFactory;
+ } In;
+ } u;
+} SUPDRVIDCREQCOMPDEREGFACTORY;
+/** Pointer to a SUPDRV IDC deregister component factory request. */
+typedef SUPDRVIDCREQCOMPDEREGFACTORY *PSUPDRVIDCREQCOMPDEREGFACTORY;
+
+
+/*
+ * The OS specific prototypes.
+ * Most OSes uses
+ */
+__BEGIN_DECLS
+
+#if defined(RT_OS_DARWIN)
+extern int VBOXCALL SUPDrvDarwinIDC(uint32_t iReq, PSUPDRVIDCREQHDR pReq);
+
+#elif defined(RT_OS_FREEBSD)
+extern int VBOXCALL SUPDrvFreeBSDIDC(uint32_t iReq, PSUPDRVIDCREQHDR pReq);
+
+#elif defined(RT_OS_LINUX)
+extern int VBOXCALL SUPDrvLinuxIDC(uint32_t iReq, PSUPDRVIDCREQHDR pReq);
+
+#elif defined(RT_OS_OS2)
+/** @todo Port to OS/2. */
+
+#elif defined(RT_OS_SOLARIS)
+extern int VBOXCALL SUPDrvSolarisIDC(uint32_t iReq, PSUPDRVIDCREQHDR pReq);
+
+#elif defined(RT_OS_WINDOWS)
+/* Nothing special for windows. */
+
+#else
+/* PORTME: OS specific IDC stuff goes here. */
+#endif
+
+__END_DECLS
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code indicating the validity of the session, request and
+ * the return data packet. The status of the request it self is found
+ * in the packet (specific to each request).
+ *
+ * @param pSession The session. (This is NULL for SUPDRV_IDC_REQ_CONNECT.)
+ * @param uReq The request number.
+ * @param pvReq Pointer to the request packet. Optional for some requests.
+ * @param cbReq The size of the request packet.
+ */
+/** @todo move this and change to function proto */
+typedef DECLCALLBACK(int) FNSUPDRVIDCENTRY(PSUPDRVSESSION pSession, uint32_t uReq, void *pvReq, uint32_t cbReq);
+
+/** @} */
+
+
+#pragma pack() /* paranoia */
+
+#endif
+
+
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIOC.h b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
new file mode 100644
index 000000000..d025dd6b9
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
@@ -0,0 +1,988 @@
+/* $Revision: 15838 $ */
+/** @file
+ * VirtualBox Support Driver - IOCtl definitions.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPDrvIOC_h___
+#define ___SUPDrvIOC_h___
+
+/*
+ * Basic types.
+ */
+#include <iprt/stdint.h>
+
+/*
+ * IOCtl numbers.
+ * We're using the Win32 type of numbers here, thus the macros below.
+ * The SUP_IOCTL_FLAG macro is used to separate requests from 32-bit
+ * and 64-bit processes.
+ */
+#ifdef RT_ARCH_AMD64
+# define SUP_IOCTL_FLAG 128
+#elif defined(RT_ARCH_X86)
+# define SUP_IOCTL_FLAG 0
+#else
+# error "dunno which arch this is!"
+#endif
+
+#ifdef RT_OS_WINDOWS
+# ifndef CTL_CODE
+# include <Windows.h>
+# endif
+ /* Automatic buffering, size not encoded. */
+# define SUP_CTL_CODE_SIZE(Function, Size) CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+# define SUP_CTL_CODE_BIG(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+# define SUP_CTL_CODE_FAST(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, (Function) | SUP_IOCTL_FLAG, METHOD_NEITHER, FILE_WRITE_ACCESS)
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) (uIOCtl)
+
+#elif defined(RT_OS_SOLARIS)
+ /* No automatic buffering, size limited to 255 bytes. */
+# include <sys/ioccom.h>
+# define SUP_CTL_CODE_SIZE(Function, Size) _IOWRN('V', (Function) | SUP_IOCTL_FLAG, sizeof(SUPREQHDR))
+# define SUP_CTL_CODE_BIG(Function) _IOWRN('V', (Function) | SUP_IOCTL_FLAG, sizeof(SUPREQHDR))
+# define SUP_CTL_CODE_FAST(Function) _IO( 'V', (Function) | SUP_IOCTL_FLAG)
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) (uIOCtl)
+
+#elif defined(RT_OS_OS2)
+ /* No automatic buffering, size not encoded. */
+# define SUP_CTL_CATEGORY 0xc0
+# define SUP_CTL_CODE_SIZE(Function, Size) ((unsigned char)(Function))
+# define SUP_CTL_CODE_BIG(Function) ((unsigned char)(Function))
+# define SUP_CTL_CATEGORY_FAST 0xc1
+# define SUP_CTL_CODE_FAST(Function) ((unsigned char)(Function))
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) (uIOCtl)
+
+#elif defined(RT_OS_LINUX)
+ /* No automatic buffering, size limited to 16KB. */
+# include <linux/ioctl.h>
+# define SUP_CTL_CODE_SIZE(Function, Size) _IOC(_IOC_READ | _IOC_WRITE, 'V', (Function) | SUP_IOCTL_FLAG, (Size))
+# define SUP_CTL_CODE_BIG(Function) _IO('V', (Function) | SUP_IOCTL_FLAG)
+# define SUP_CTL_CODE_FAST(Function) _IO('V', (Function) | SUP_IOCTL_FLAG)
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) ((uIOCtl) & ~IOCSIZE_MASK)
+
+#elif defined(RT_OS_L4)
+ /* Implemented in suplib, no worries. */
+# define SUP_CTL_CODE_SIZE(Function, Size) (Function)
+# define SUP_CTL_CODE_BIG(Function) (Function)
+# define SUP_CTL_CODE_FAST(Function) (Function)
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) (uIOCtl)
+
+#else /* BSD Like */
+ /* Automatic buffering, size limited to 4KB on *BSD and 8KB on Darwin - commands the limit, 4KB. */
+# include <sys/ioccom.h>
+# define SUP_CTL_CODE_SIZE(Function, Size) _IOC(IOC_INOUT, 'V', (Function) | SUP_IOCTL_FLAG, (Size))
+# define SUP_CTL_CODE_BIG(Function) _IO('V', (Function) | SUP_IOCTL_FLAG)
+# define SUP_CTL_CODE_FAST(Function) _IO('V', (Function) | SUP_IOCTL_FLAG)
+# define SUP_CTL_CODE_NO_SIZE(uIOCtl) ( (uIOCtl) & ~_IOC(0,0,0,IOCPARM_MASK) )
+#endif
+
+/** Fast path IOCtl: VMMR0_DO_RAW_RUN */
+#define SUP_IOCTL_FAST_DO_RAW_RUN SUP_CTL_CODE_FAST(64)
+/** Fast path IOCtl: VMMR0_DO_HWACC_RUN */
+#define SUP_IOCTL_FAST_DO_HWACC_RUN SUP_CTL_CODE_FAST(65)
+/** Just a NOP call for profiling the latency of a fast ioctl call to VMMR0. */
+#define SUP_IOCTL_FAST_DO_NOP SUP_CTL_CODE_FAST(66)
+
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+#ifdef RT_ARCH_AMD64
+# pragma pack(8) /* paranoia. */
+#else
+# pragma pack(4) /* paranoia. */
+#endif
+
+
+/**
+ * Common In/Out header.
+ */
+typedef struct SUPREQHDR
+{
+ /** Cookie. */
+ uint32_t u32Cookie;
+ /** Session cookie. */
+ uint32_t u32SessionCookie;
+ /** The size of the input. */
+ uint32_t cbIn;
+ /** The size of the output. */
+ uint32_t cbOut;
+ /** Flags. See SUPREQHDR_FLAGS_* for details and values. */
+ uint32_t fFlags;
+ /** The VBox status code of the operation, out direction only. */
+ int32_t rc;
+} SUPREQHDR;
+/** Pointer to a IOC header. */
+typedef SUPREQHDR *PSUPREQHDR;
+
+/** @name SUPREQHDR::fFlags values
+ * @{ */
+/** Masks out the magic value. */
+#define SUPREQHDR_FLAGS_MAGIC_MASK UINT32_C(0xff0000ff)
+/** The generic mask. */
+#define SUPREQHDR_FLAGS_GEN_MASK UINT32_C(0x0000ff00)
+/** The request specific mask. */
+#define SUPREQHDR_FLAGS_REQ_MASK UINT32_C(0x00ff0000)
+
+/** There is extra input that needs copying on some platforms. */
+#define SUPREQHDR_FLAGS_EXTRA_IN UINT32_C(0x00000100)
+/** There is extra output that needs copying on some platforms. */
+#define SUPREQHDR_FLAGS_EXTRA_OUT UINT32_C(0x00000200)
+
+/** The magic value. */
+#define SUPREQHDR_FLAGS_MAGIC UINT32_C(0x42000042)
+/** The default value. Use this when no special stuff is requested. */
+#define SUPREQHDR_FLAGS_DEFAULT SUPREQHDR_FLAGS_MAGIC
+/** @} */
+
+
+/** @name SUP_IOCTL_COOKIE
+ * @{
+ */
+/** Negotiate cookie. */
+#define SUP_IOCTL_COOKIE SUP_CTL_CODE_SIZE(1, SUP_IOCTL_COOKIE_SIZE)
+/** The request size. */
+#define SUP_IOCTL_COOKIE_SIZE sizeof(SUPCOOKIE)
+/** The SUPREQHDR::cbIn value. */
+#define SUP_IOCTL_COOKIE_SIZE_IN sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPCOOKIE, u.In)
+/** The SUPREQHDR::cbOut value. */
+#define SUP_IOCTL_COOKIE_SIZE_OUT sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPCOOKIE, u.Out)
+/** SUPCOOKIE_IN magic word. */
+#define SUPCOOKIE_MAGIC "The Magic Word!"
+/** The initial cookie. */
+#define SUPCOOKIE_INITIAL_COOKIE 0x69726f74 /* 'tori' */
+
+/** Current interface version.
+ * The upper 16-bit is the major version, the the lower the minor version.
+ * When incompatible changes are made, the upper major number has to be changed.
+ *
+ * @todo Pending work on next major version change:
+ * - Eliminate supdrvPageWasLockedByPageAlloc and supdrvPageGetPhys.
+ * - Remove SUPR0PageAlloc in favor of SUPR0PageAllocEx, removing
+ * and renaming the related IOCtls too.
+ */
+#define SUPDRV_IOC_VERSION 0x000a0009
+
+/** SUP_IOCTL_COOKIE. */
+typedef struct SUPCOOKIE
+{
+ /** The header.
+ * u32Cookie must be set to SUPCOOKIE_INITIAL_COOKIE.
+ * u32SessionCookie should be set to some random value. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Magic word. */
+ char szMagic[16];
+ /** The requested interface version number. */
+ uint32_t u32ReqVersion;
+ /** The minimum interface version number. */
+ uint32_t u32MinVersion;
+ } In;
+ struct
+ {
+ /** Cookie. */
+ uint32_t u32Cookie;
+ /** Session cookie. */
+ uint32_t u32SessionCookie;
+ /** Interface version for this session. */
+ uint32_t u32SessionVersion;
+ /** The actual interface version in the driver. */
+ uint32_t u32DriverVersion;
+ /** Number of functions available for the SUP_IOCTL_QUERY_FUNCS request. */
+ uint32_t cFunctions;
+ /** Session handle. */
+ R0PTRTYPE(PSUPDRVSESSION) pSession;
+ } Out;
+ } u;
+} SUPCOOKIE, *PSUPCOOKIE;
+/** @} */
+
+
+/** @name SUP_IOCTL_QUERY_FUNCS
+ * Query SUPR0 functions.
+ * @{
+ */
+#define SUP_IOCTL_QUERY_FUNCS(cFuncs) SUP_CTL_CODE_SIZE(2, SUP_IOCTL_QUERY_FUNCS_SIZE(cFuncs))
+#define SUP_IOCTL_QUERY_FUNCS_SIZE(cFuncs) RT_UOFFSETOF(SUPQUERYFUNCS, u.Out.aFunctions[(cFuncs)])
+#define SUP_IOCTL_QUERY_FUNCS_SIZE_IN sizeof(SUPREQHDR)
+#define SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(cFuncs) SUP_IOCTL_QUERY_FUNCS_SIZE(cFuncs)
+
+/** A function. */
+typedef struct SUPFUNC
+{
+ /** Name - mangled. */
+ char szName[32];
+ /** Address. */
+ RTR0PTR pfn;
+} SUPFUNC, *PSUPFUNC;
+
+typedef struct SUPQUERYFUNCS
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Number of functions returned. */
+ uint32_t cFunctions;
+ /** Array of functions. */
+ SUPFUNC aFunctions[1];
+ } Out;
+ } u;
+} SUPQUERYFUNCS, *PSUPQUERYFUNCS;
+/** @} */
+
+
+/** @name SUP_IOCTL_IDT_INSTALL
+ * Install IDT patch for calling processor.
+ * @{
+ */
+#define SUP_IOCTL_IDT_INSTALL SUP_CTL_CODE_SIZE(3, SUP_IOCTL_IDT_INSTALL_SIZE)
+#define SUP_IOCTL_IDT_INSTALL_SIZE sizeof(SUPIDTINSTALL)
+#define SUP_IOCTL_IDT_INSTALL_SIZE_IN sizeof(SUPREQHDR)
+#define SUP_IOCTL_IDT_INSTALL_SIZE_OUT sizeof(SUPIDTINSTALL)
+typedef struct SUPIDTINSTALL
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The IDT entry number. */
+ uint8_t u8Idt;
+ } Out;
+ } u;
+} SUPIDTINSTALL, *PSUPIDTINSTALL;
+/** @} */
+
+
+/** @name SUP_IOCTL_IDT_REMOVE
+ * Remove IDT patch for calling processor.
+ * @{
+ */
+#define SUP_IOCTL_IDT_REMOVE SUP_CTL_CODE_SIZE(4, SUP_IOCTL_IDT_REMOVE_SIZE)
+#define SUP_IOCTL_IDT_REMOVE_SIZE sizeof(SUPIDTREMOVE)
+#define SUP_IOCTL_IDT_REMOVE_SIZE_IN sizeof(SUPIDTREMOVE)
+#define SUP_IOCTL_IDT_REMOVE_SIZE_OUT sizeof(SUPIDTREMOVE)
+typedef struct SUPIDTREMOVE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+} SUPIDTREMOVE, *PSUPIDTREMOVE;
+/** @}*/
+
+
+/** @name SUP_IOCTL_LDR_OPEN
+ * Open an image.
+ * @{
+ */
+#define SUP_IOCTL_LDR_OPEN SUP_CTL_CODE_SIZE(5, SUP_IOCTL_LDR_OPEN_SIZE)
+#define SUP_IOCTL_LDR_OPEN_SIZE sizeof(SUPLDROPEN)
+#define SUP_IOCTL_LDR_OPEN_SIZE_IN sizeof(SUPLDROPEN)
+#define SUP_IOCTL_LDR_OPEN_SIZE_OUT (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPLDROPEN, u.Out))
+typedef struct SUPLDROPEN
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Size of the image we'll be loading. */
+ uint32_t cbImage;
+ /** Image name.
+ * This is the NAME of the image, not the file name. It is used
+ * to share code with other processes. (Max len is 32 chars!) */
+ char szName[32];
+ } In;
+ struct
+ {
+ /** The base address of the image. */
+ RTR0PTR pvImageBase;
+ /** Indicate whether or not the image requires loading. */
+ bool fNeedsLoading;
+ } Out;
+ } u;
+} SUPLDROPEN, *PSUPLDROPEN;
+/** @} */
+
+
+/** @name SUP_IOCTL_LDR_LOAD
+ * Upload the image bits.
+ * @{
+ */
+#define SUP_IOCTL_LDR_LOAD SUP_CTL_CODE_BIG(6)
+#define SUP_IOCTL_LDR_LOAD_SIZE(cbImage) RT_UOFFSETOF(SUPLDRLOAD, u.In.achImage[cbImage])
+#define SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImage) RT_UOFFSETOF(SUPLDRLOAD, u.In.achImage[cbImage])
+#define SUP_IOCTL_LDR_LOAD_SIZE_OUT sizeof(SUPREQHDR)
+
+/**
+ * Module initialization callback function.
+ * This is called once after the module has been loaded.
+ *
+ * @returns 0 on success.
+ * @returns Appropriate error code on failure.
+ */
+typedef DECLCALLBACK(int) FNR0MODULEINIT(void);
+/** Pointer to a FNR0MODULEINIT(). */
+typedef R0PTRTYPE(FNR0MODULEINIT *) PFNR0MODULEINIT;
+
+/**
+ * Module termination callback function.
+ * This is called once right before the module is being unloaded.
+ */
+typedef DECLCALLBACK(void) FNR0MODULETERM(void);
+/** Pointer to a FNR0MODULETERM(). */
+typedef R0PTRTYPE(FNR0MODULETERM *) PFNR0MODULETERM;
+
+/**
+ * Symbol table entry.
+ */
+typedef struct SUPLDRSYM
+{
+ /** Offset into of the string table. */
+ uint32_t offName;
+ /** Offset of the symbol relative to the image load address. */
+ uint32_t offSymbol;
+} SUPLDRSYM;
+/** Pointer to a symbol table entry. */
+typedef SUPLDRSYM *PSUPLDRSYM;
+/** Pointer to a const symbol table entry. */
+typedef SUPLDRSYM const *PCSUPLDRSYM;
+
+/**
+ * SUPLDRLOAD::u::In::EP type.
+ */
+typedef enum SUPLDRLOADEP
+{
+ SUPLDRLOADEP_NOTHING = 0,
+ SUPLDRLOADEP_VMMR0,
+ SUPLDRLOADEP_SERVICE,
+ SUPLDRLOADEP_32BIT_HACK = 0x7fffffff
+} SUPLDRLOADEP;
+
+typedef struct SUPLDRLOAD
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The address of module initialization function. Similar to _DLL_InitTerm(hmod, 0). */
+ PFNR0MODULEINIT pfnModuleInit;
+ /** The address of module termination function. Similar to _DLL_InitTerm(hmod, 1). */
+ PFNR0MODULETERM pfnModuleTerm;
+ /** Special entry points. */
+ union
+ {
+ /** SUPLDRLOADEP_VMMR0. */
+ struct
+ {
+ /** The module handle (i.e. address). */
+ RTR0PTR pvVMMR0;
+ /** Address of VMMR0EntryInt function. */
+ RTR0PTR pvVMMR0EntryInt;
+ /** Address of VMMR0EntryFast function. */
+ RTR0PTR pvVMMR0EntryFast;
+ /** Address of VMMR0EntryEx function. */
+ RTR0PTR pvVMMR0EntryEx;
+ } VMMR0;
+ /** SUPLDRLOADEP_SERVICE. */
+ struct
+ {
+ /** The service request handler.
+ * (PFNR0SERVICEREQHANDLER isn't defined yet.) */
+ RTR0PTR pfnServiceReq;
+ /** Reserved, must be NIL. */
+ RTR0PTR apvReserved[3];
+ } Service;
+ } EP;
+ /** Address. */
+ RTR0PTR pvImageBase;
+ /** Entry point type. */
+ SUPLDRLOADEP eEPType;
+ /** The offset of the symbol table. */
+ uint32_t offSymbols;
+ /** The number of entries in the symbol table. */
+ uint32_t cSymbols;
+ /** The offset of the string table. */
+ uint32_t offStrTab;
+ /** Size of the string table. */
+ uint32_t cbStrTab;
+ /** Size of image (including string and symbol tables). */
+ uint32_t cbImage;
+ /** The image data. */
+ char achImage[1];
+ } In;
+ } u;
+} SUPLDRLOAD, *PSUPLDRLOAD;
+/** @} */
+
+
+/** @name SUP_IOCTL_LDR_FREE
+ * Free an image.
+ * @{
+ */
+#define SUP_IOCTL_LDR_FREE SUP_CTL_CODE_SIZE(7, SUP_IOCTL_LDR_FREE_SIZE)
+#define SUP_IOCTL_LDR_FREE_SIZE sizeof(SUPLDRFREE)
+#define SUP_IOCTL_LDR_FREE_SIZE_IN sizeof(SUPLDRFREE)
+#define SUP_IOCTL_LDR_FREE_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPLDRFREE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Address. */
+ RTR0PTR pvImageBase;
+ } In;
+ } u;
+} SUPLDRFREE, *PSUPLDRFREE;
+/** @} */
+
+
+/** @name SUP_IOCTL_LDR_GET_SYMBOL
+ * Get address of a symbol within an image.
+ * @{
+ */
+#define SUP_IOCTL_LDR_GET_SYMBOL SUP_CTL_CODE_SIZE(8, SUP_IOCTL_LDR_GET_SYMBOL_SIZE)
+#define SUP_IOCTL_LDR_GET_SYMBOL_SIZE sizeof(SUPLDRGETSYMBOL)
+#define SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN sizeof(SUPLDRGETSYMBOL)
+#define SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPLDRGETSYMBOL, u.Out))
+typedef struct SUPLDRGETSYMBOL
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Address. */
+ RTR0PTR pvImageBase;
+ /** The symbol name. */
+ char szSymbol[64];
+ } In;
+ struct
+ {
+ /** The symbol address. */
+ RTR0PTR pvSymbol;
+ } Out;
+ } u;
+} SUPLDRGETSYMBOL, *PSUPLDRGETSYMBOL;
+/** @} */
+
+
+/** @name SUP_IOCTL_CALL_VMMR0
+ * Call the R0 VMM Entry point.
+ *
+ * @todo Might have to convert this to a big request...
+ * @{
+ */
+#define SUP_IOCTL_CALL_VMMR0(cbReq) SUP_CTL_CODE_SIZE(9, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq))
+#define SUP_IOCTL_CALL_VMMR0_SIZE(cbReq) RT_UOFFSETOF(SUPCALLVMMR0, abReqPkt[cbReq])
+#define SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq) SUP_IOCTL_CALL_VMMR0_SIZE(cbReq)
+#define SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq) SUP_IOCTL_CALL_VMMR0_SIZE(cbReq)
+typedef struct SUPCALLVMMR0
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The VM handle. */
+ PVMR0 pVMR0;
+ /** Which operation to execute. */
+ uint32_t uOperation;
+#if R0_ARCH_BITS == 64
+ /** Alignment. */
+ uint32_t u32Reserved;
+#endif
+ /** Argument to use when no request packet is supplied. */
+ uint64_t u64Arg;
+ } In;
+ } u;
+ /** The VMMR0Entry request packet. */
+ uint8_t abReqPkt[1];
+} SUPCALLVMMR0, *PSUPCALLVMMR0;
+/** @} */
+
+
+/** @name SUP_IOCTL_LOW_ALLOC
+ * Allocate memory below 4GB (physically).
+ * @{
+ */
+#define SUP_IOCTL_LOW_ALLOC SUP_CTL_CODE_BIG(10)
+#define SUP_IOCTL_LOW_ALLOC_SIZE(cPages) ((uint32_t)RT_UOFFSETOF(SUPLOWALLOC, u.Out.aPages[cPages]))
+#define SUP_IOCTL_LOW_ALLOC_SIZE_IN (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPLOWALLOC, u.In))
+#define SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages) SUP_IOCTL_LOW_ALLOC_SIZE(cPages)
+typedef struct SUPLOWALLOC
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Number of pages to allocate. */
+ uint32_t cPages;
+ } In;
+ struct
+ {
+ /** The ring-3 address of the allocated memory. */
+ RTR3PTR pvR3;
+ /** The ring-0 address of the allocated memory. */
+ RTR0PTR pvR0;
+ /** Array of pages. */
+ RTHCPHYS aPages[1];
+ } Out;
+ } u;
+} SUPLOWALLOC, *PSUPLOWALLOC;
+/** @} */
+
+
+/** @name SUP_IOCTL_LOW_FREE
+ * Free low memory.
+ * @{
+ */
+#define SUP_IOCTL_LOW_FREE SUP_CTL_CODE_SIZE(11, SUP_IOCTL_LOW_FREE_SIZE)
+#define SUP_IOCTL_LOW_FREE_SIZE sizeof(SUPLOWFREE)
+#define SUP_IOCTL_LOW_FREE_SIZE_IN sizeof(SUPLOWFREE)
+#define SUP_IOCTL_LOW_FREE_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPLOWFREE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The ring-3 address of the memory to free. */
+ RTR3PTR pvR3;
+ } In;
+ } u;
+} SUPLOWFREE, *PSUPLOWFREE;
+/** @} */
+
+
+/** @name SUP_IOCTL_PAGE_ALLOC
+ * Allocate memory and map into the user process.
+ * The memory is of course locked.
+ * @{
+ */
+#define SUP_IOCTL_PAGE_ALLOC SUP_CTL_CODE_BIG(12)
+#define SUP_IOCTL_PAGE_ALLOC_SIZE(cPages) RT_UOFFSETOF(SUPPAGEALLOC, u.Out.aPages[cPages])
+#define SUP_IOCTL_PAGE_ALLOC_SIZE_IN (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPPAGEALLOC, u.In))
+#define SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(cPages) SUP_IOCTL_PAGE_ALLOC_SIZE(cPages)
+typedef struct SUPPAGEALLOC
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Number of pages to allocate */
+ uint32_t cPages;
+ } In;
+ struct
+ {
+ /** Returned ring-3 address. */
+ RTR3PTR pvR3;
+ /** The physical addresses of the allocated pages. */
+ RTHCPHYS aPages[1];
+ } Out;
+ } u;
+} SUPPAGEALLOC, *PSUPPAGEALLOC;
+/** @} */
+
+
+/** @name SUP_IOCTL_PAGE_FREE
+ * Free memory allocated with SUP_IOCTL_PAGE_ALLOC or SUP_IOCTL_PAGE_ALLOC_EX.
+ * @{
+ */
+#define SUP_IOCTL_PAGE_FREE SUP_CTL_CODE_SIZE(13, SUP_IOCTL_PAGE_FREE_SIZE_IN)
+#define SUP_IOCTL_PAGE_FREE_SIZE sizeof(SUPPAGEFREE)
+#define SUP_IOCTL_PAGE_FREE_SIZE_IN sizeof(SUPPAGEFREE)
+#define SUP_IOCTL_PAGE_FREE_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPPAGEFREE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Address of memory range to free. */
+ RTR3PTR pvR3;
+ } In;
+ } u;
+} SUPPAGEFREE, *PSUPPAGEFREE;
+/** @} */
+
+
+/** @name SUP_IOCTL_PAGE_LOCK
+ * Pin down physical pages.
+ * @{
+ */
+#define SUP_IOCTL_PAGE_LOCK SUP_CTL_CODE_BIG(14)
+#define SUP_IOCTL_PAGE_LOCK_SIZE(cPages) (RT_MAX((size_t)SUP_IOCTL_PAGE_LOCK_SIZE_IN, (size_t)SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages)))
+#define SUP_IOCTL_PAGE_LOCK_SIZE_IN (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPPAGELOCK, u.In))
+#define SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages) RT_UOFFSETOF(SUPPAGELOCK, u.Out.aPages[cPages])
+typedef struct SUPPAGELOCK
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Start of page range. Must be PAGE aligned. */
+ RTR3PTR pvR3;
+ /** The range size given as a page count. */
+ uint32_t cPages;
+ } In;
+
+ struct
+ {
+ /** Array of pages. */
+ RTHCPHYS aPages[1];
+ } Out;
+ } u;
+} SUPPAGELOCK, *PSUPPAGELOCK;
+/** @} */
+
+
+/** @name SUP_IOCTL_PAGE_UNLOCK
+ * Unpin physical pages.
+ * @{ */
+#define SUP_IOCTL_PAGE_UNLOCK SUP_CTL_CODE_SIZE(15, SUP_IOCTL_PAGE_UNLOCK_SIZE)
+#define SUP_IOCTL_PAGE_UNLOCK_SIZE sizeof(SUPPAGEUNLOCK)
+#define SUP_IOCTL_PAGE_UNLOCK_SIZE_IN sizeof(SUPPAGEUNLOCK)
+#define SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPPAGEUNLOCK
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Start of page range of a range previuosly pinned. */
+ RTR3PTR pvR3;
+ } In;
+ } u;
+} SUPPAGEUNLOCK, *PSUPPAGEUNLOCK;
+/** @} */
+
+
+/** @name SUP_IOCTL_CONT_ALLOC
+ * Allocate contious memory.
+ * @{
+ */
+#define SUP_IOCTL_CONT_ALLOC SUP_CTL_CODE_SIZE(16, SUP_IOCTL_CONT_ALLOC_SIZE)
+#define SUP_IOCTL_CONT_ALLOC_SIZE sizeof(SUPCONTALLOC)
+#define SUP_IOCTL_CONT_ALLOC_SIZE_IN (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPCONTALLOC, u.In))
+#define SUP_IOCTL_CONT_ALLOC_SIZE_OUT sizeof(SUPCONTALLOC)
+typedef struct SUPCONTALLOC
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The allocation size given as a page count. */
+ uint32_t cPages;
+ } In;
+
+ struct
+ {
+ /** The address of the ring-0 mapping of the allocated memory. */
+ RTR0PTR pvR0;
+ /** The address of the ring-3 mapping of the allocated memory. */
+ RTR3PTR pvR3;
+ /** The physical address of the allocation. */
+ RTHCPHYS HCPhys;
+ } Out;
+ } u;
+} SUPCONTALLOC, *PSUPCONTALLOC;
+/** @} */
+
+
+/** @name SUP_IOCTL_CONT_FREE Input.
+ * @{
+ */
+/** Free contious memory. */
+#define SUP_IOCTL_CONT_FREE SUP_CTL_CODE_SIZE(17, SUP_IOCTL_CONT_FREE_SIZE)
+#define SUP_IOCTL_CONT_FREE_SIZE sizeof(SUPCONTFREE)
+#define SUP_IOCTL_CONT_FREE_SIZE_IN sizeof(SUPCONTFREE)
+#define SUP_IOCTL_CONT_FREE_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPCONTFREE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The ring-3 address of the memory to free. */
+ RTR3PTR pvR3;
+ } In;
+ } u;
+} SUPCONTFREE, *PSUPCONTFREE;
+/** @} */
+
+
+/** @name SUP_IOCTL_GET_PAGING_MODE
+ * Get the host paging mode.
+ * @{
+ */
+#define SUP_IOCTL_GET_PAGING_MODE SUP_CTL_CODE_SIZE(18, SUP_IOCTL_GET_PAGING_MODE_SIZE)
+#define SUP_IOCTL_GET_PAGING_MODE_SIZE sizeof(SUPGETPAGINGMODE)
+#define SUP_IOCTL_GET_PAGING_MODE_SIZE_IN sizeof(SUPREQHDR)
+#define SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT sizeof(SUPGETPAGINGMODE)
+typedef struct SUPGETPAGINGMODE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The paging mode. */
+ SUPPAGINGMODE enmMode;
+ } Out;
+ } u;
+} SUPGETPAGINGMODE, *PSUPGETPAGINGMODE;
+/** @} */
+
+
+/** @name SUP_IOCTL_SET_VM_FOR_FAST
+ * Set the VM handle for doing fast call ioctl calls.
+ * @{
+ */
+#define SUP_IOCTL_SET_VM_FOR_FAST SUP_CTL_CODE_SIZE(19, SUP_IOCTL_SET_VM_FOR_FAST_SIZE)
+#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE sizeof(SUPSETVMFORFAST)
+#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN sizeof(SUPSETVMFORFAST)
+#define SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT sizeof(SUPREQHDR)
+typedef struct SUPSETVMFORFAST
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The ring-0 VM handle (pointer). */
+ PVMR0 pVMR0;
+ } In;
+ } u;
+} SUPSETVMFORFAST, *PSUPSETVMFORFAST;
+/** @} */
+
+
+/** @name SUP_IOCTL_GIP_MAP
+ * Map the GIP into user space.
+ * @{
+ */
+#define SUP_IOCTL_GIP_MAP SUP_CTL_CODE_SIZE(20, SUP_IOCTL_GIP_MAP_SIZE)
+#define SUP_IOCTL_GIP_MAP_SIZE sizeof(SUPGIPMAP)
+#define SUP_IOCTL_GIP_MAP_SIZE_IN sizeof(SUPREQHDR)
+#define SUP_IOCTL_GIP_MAP_SIZE_OUT sizeof(SUPGIPMAP)
+typedef struct SUPGIPMAP
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The physical address of the GIP. */
+ RTHCPHYS HCPhysGip;
+ /** Pointer to the read-only usermode GIP mapping for this session. */
+ R3PTRTYPE(PSUPGLOBALINFOPAGE) pGipR3;
+ /** Pointer to the supervisor mode GIP mapping. */
+ R0PTRTYPE(PSUPGLOBALINFOPAGE) pGipR0;
+ } Out;
+ } u;
+} SUPGIPMAP, *PSUPGIPMAP;
+/** @} */
+
+
+/** @name SUP_IOCTL_GIP_UNMAP
+ * Unmap the GIP.
+ * @{
+ */
+#define SUP_IOCTL_GIP_UNMAP SUP_CTL_CODE_SIZE(21, SUP_IOCTL_GIP_UNMAP_SIZE)
+#define SUP_IOCTL_GIP_UNMAP_SIZE sizeof(SUPGIPUNMAP)
+#define SUP_IOCTL_GIP_UNMAP_SIZE_IN sizeof(SUPGIPUNMAP)
+#define SUP_IOCTL_GIP_UNMAP_SIZE_OUT sizeof(SUPGIPUNMAP)
+typedef struct SUPGIPUNMAP
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+} SUPGIPUNMAP, *PSUPGIPUNMAP;
+/** @} */
+
+
+/** @name SUP_IOCTL_CALL_SERVICE
+ * Call the a ring-0 service.
+ *
+ * @todo Might have to convert this to a big request, just like
+ * SUP_IOCTL_CALL_VMMR0
+ * @{
+ */
+#define SUP_IOCTL_CALL_SERVICE(cbReq) SUP_CTL_CODE_SIZE(22, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq))
+#define SUP_IOCTL_CALL_SERVICE_SIZE(cbReq) RT_UOFFSETOF(SUPCALLSERVICE, abReqPkt[cbReq])
+#define SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq) SUP_IOCTL_CALL_SERVICE_SIZE(cbReq)
+#define SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq) SUP_IOCTL_CALL_SERVICE_SIZE(cbReq)
+typedef struct SUPCALLSERVICE
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The service name. */
+ char szName[28];
+ /** Which operation to execute. */
+ uint32_t uOperation;
+ /** Argument to use when no request packet is supplied. */
+ uint64_t u64Arg;
+ } In;
+ } u;
+ /** The request packet passed to SUP. */
+ uint8_t abReqPkt[1];
+} SUPCALLSERVICE, *PSUPCALLSERVICE;
+/** @} */
+
+/** @name SUP_IOCTL_PAGE_ALLOC_EX
+ * Allocate memory and map it into kernel and/or user space. The memory is of
+ * course locked. This is an extended version of SUP_IOCTL_PAGE_ALLOC and the
+ * result should be freed using SUP_IOCTL_PAGE_FREE.
+ *
+ * @remarks Allocations without a kernel mapping may fail with
+ * VERR_NOT_SUPPORTED on some platforms just like with
+ * SUP_IOCTL_PAGE_ALLOC.
+ *
+ * @{
+ */
+#define SUP_IOCTL_PAGE_ALLOC_EX SUP_CTL_CODE_BIG(23)
+#define SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages) RT_UOFFSETOF(SUPPAGEALLOCEX, u.Out.aPages[cPages])
+#define SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN (sizeof(SUPREQHDR) + RT_SIZEOFMEMB(SUPPAGEALLOCEX, u.In))
+#define SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages) SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages)
+typedef struct SUPPAGEALLOCEX
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** Number of pages to allocate */
+ uint32_t cPages;
+ /** Whether it should have kernel mapping. */
+ bool fKernelMapping;
+ /** Whether it should have a user mapping. */
+ bool fUserMapping;
+ /** Reserved. Must be false. */
+ bool fReserved0;
+ /** Reserved. Must be false. */
+ bool fReserved1;
+ } In;
+ struct
+ {
+ /** Returned ring-3 address. */
+ RTR3PTR pvR3;
+ /** Returned ring-0 address. */
+ RTR0PTR pvR0;
+ /** The physical addresses of the allocated pages. */
+ RTHCPHYS aPages[1];
+ } Out;
+ } u;
+} SUPPAGEALLOCEX, *PSUPPAGEALLOCEX;
+/** @} */
+
+
+/** @name SUP_IOCTL_PAGE_MAP_KERNEL
+ * Maps a portion of memory allocated by SUP_IOCTL_PAGE_ALLOC_EX /
+ * SUPR0PageAllocEx into kernel space for use by a device or similar.
+ *
+ * The mapping will be freed together with the ring-3 mapping when
+ * SUP_IOCTL_PAGE_FREE or SUPR0PageFree is called.
+ *
+ * @remarks Not necessarily supported on all platforms.
+ *
+ * @{
+ */
+#define SUP_IOCTL_PAGE_MAP_KERNEL SUP_CTL_CODE_SIZE(24, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE)
+#define SUP_IOCTL_PAGE_MAP_KERNEL_SIZE sizeof(SUPPAGEMAPKERNEL)
+#define SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN sizeof(SUPPAGEMAPKERNEL)
+#define SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT sizeof(SUPPAGEMAPKERNEL)
+typedef struct SUPPAGEMAPKERNEL
+{
+ /** The header. */
+ SUPREQHDR Hdr;
+ union
+ {
+ struct
+ {
+ /** The pointer of to the previously allocated memory. */
+ RTR3PTR pvR3;
+ /** The offset to start mapping from. */
+ uint32_t offSub;
+ /** Size of the section to map. */
+ uint32_t cbSub;
+ /** Flags reserved for future fun. */
+ uint32_t fFlags;
+ } In;
+ struct
+ {
+ /** The ring-0 address corresponding to pvR3 + offSub. */
+ RTR0PTR pvR0;
+ } Out;
+ } u;
+} SUPPAGEMAPKERNEL, *PSUPPAGEMAPKERNEL;
+/** @} */
+
+
+#pragma pack() /* paranoia */
+
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/SUPDrvInternal.h b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
new file mode 100644
index 000000000..5ae9c8b49
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
@@ -0,0 +1,641 @@
+/* $Revision: 16029 $ */
+/** @file
+ * VirtualBox Support Driver - Internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPDrvInternal_h
+#define ___SUPDrvInternal_h
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <VBox/sup.h>
+#include <iprt/memobj.h>
+#include <iprt/time.h>
+#include <iprt/timer.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+
+#if defined(RT_OS_WINDOWS)
+ __BEGIN_DECLS
+# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
+# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
+# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
+# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
+# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
+# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap
+# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap
+# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap
+# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap
+# include <ntddk.h>
+# undef _InterlockedExchange
+# undef _InterlockedExchangeAdd
+# undef _InterlockedCompareExchange
+# undef _InterlockedAddLargeStatistic
+# undef _interlockedbittestandset
+# undef _interlockedbittestandreset
+# undef _interlockedbittestandset64
+# undef _interlockedbittestandreset64
+# else
+# include <ntddk.h>
+# endif
+# include <memory.h>
+# define memcmp(a,b,c) mymemcmp(a,b,c)
+ int VBOXCALL mymemcmp(const void *, const void *, size_t);
+ __END_DECLS
+
+#elif defined(RT_OS_LINUX)
+# include <linux/autoconf.h>
+# include <linux/version.h>
+# if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+# define MODVERSIONS
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71)
+# include <linux/modversions.h>
+# endif
+# endif
+# if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
+# undef ALIGN
+# endif
+# ifndef KBUILD_STR
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
+# define KBUILD_STR(s) s
+# else
+# define KBUILD_STR(s) #s
+# endif
+# endif
+# include <linux/string.h>
+# include <linux/spinlock.h>
+# include <linux/slab.h>
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+# include <linux/semaphore.h>
+# else /* older kernels */
+# include <asm/semaphore.h>
+# endif /* older kernels */
+# include <linux/timer.h>
+
+# if 0
+# include <linux/hrtimer.h>
+# define VBOX_HRTIMER
+# endif
+
+#elif defined(RT_OS_DARWIN)
+# include <libkern/libkern.h>
+# include <iprt/string.h>
+
+#elif defined(RT_OS_OS2)
+
+#elif defined(RT_OS_FREEBSD)
+# define memset libkern_memset /** @todo these are just hacks to get it compiling, check out later. */
+# define memcmp libkern_memcmp
+# define strchr libkern_strchr
+# define strrchr libkern_strrchr
+# define ffs libkern_ffs
+# define ffsl libkern_ffsl
+# define fls libkern_fls
+# define flsl libkern_flsl
+# include <sys/libkern.h>
+# undef memset
+# undef memcmp
+# undef strchr
+# undef strrchr
+# undef ffs
+# undef ffsl
+# undef fls
+# undef flsl
+# include <iprt/string.h>
+
+#elif defined(RT_OS_SOLARIS)
+# include <sys/cmn_err.h>
+# include <iprt/string.h>
+
+#else
+# error "unsupported OS."
+#endif
+
+#include "SUPDrvIOC.h"
+#include "SUPDrvIDC.h"
+
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/*
+ * Hardcoded cookies.
+ */
+#define BIRD 0x64726962 /* 'bird' */
+#define BIRD_INV 0x62697264 /* 'drib' */
+
+
+/*
+ * Win32
+ */
+#if defined(RT_OS_WINDOWS)
+
+/* debug printf */
+# define OSDBGPRINT(a) DbgPrint a
+
+/** Maximum number of bytes we try to lock down in one go.
+ * This is supposed to have a limit right below 256MB, but this appears
+ * to actually be much lower. The values here have been determined experimentally.
+ */
+#ifdef RT_ARCH_X86
+# define MAX_LOCK_MEM_SIZE (32*1024*1024) /* 32mb */
+#endif
+#ifdef RT_ARCH_AMD64
+# define MAX_LOCK_MEM_SIZE (24*1024*1024) /* 24mb */
+#endif
+
+
+/*
+ * Linux
+ */
+#elif defined(RT_OS_LINUX)
+
+/* check kernel version */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+# error Unsupported kernel version!
+#endif
+
+__BEGIN_DECLS
+int linux_dprintf(const char *format, ...);
+__END_DECLS
+
+/* debug printf */
+# define OSDBGPRINT(a) printk a
+
+
+/*
+ * Darwin
+ */
+#elif defined(RT_OS_DARWIN)
+
+/* debug printf */
+# define OSDBGPRINT(a) printf a
+
+
+/*
+ * OS/2
+ */
+#elif defined(RT_OS_OS2)
+
+/* No log API in OS/2 only COM port. */
+# define OSDBGPRINT(a) SUPR0Printf a
+
+
+/*
+ * FreeBSD
+ */
+#elif defined(RT_OS_FREEBSD)
+
+/* debug printf */
+# define OSDBGPRINT(a) printf a
+
+
+/*
+ * Solaris
+ */
+#elif defined(RT_OS_SOLARIS)
+# define OSDBGPRINT(a) SUPR0Printf a
+
+
+#else
+/** @todo other os'es */
+# error "OS interface defines is not done for this OS!"
+#endif
+
+
+/* dprintf */
+#if (defined(DEBUG) && !defined(NO_LOGGING)) || defined(RT_OS_FREEBSD)
+# ifdef LOG_TO_COM
+# include <VBox/log.h>
+# define dprintf(a) RTLogComPrintf a
+# else
+# define dprintf(a) OSDBGPRINT(a)
+# endif
+#else
+# define dprintf(a) do {} while (0)
+#endif
+
+/* dprintf2 - extended logging. */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_OS2) || defined(RT_OS_FREEBSD)
+# define dprintf2 dprintf
+#else
+# define dprintf2(a) do { } while (0)
+#endif
+
+
+/** @def RT_WITH_W64_UNWIND_HACK
+ * Changes a function name into the wrapped version if we've
+ * enabled the unwind hack.
+ *
+ * The unwind hack is for making the NT unwind procedures skip
+ * our dynamically loaded code when they try to walk the call
+ * stack. Needless to say, they kind of don't expect what
+ * we're doing here and get kind of confused and may BSOD. */
+#ifdef DOXYGEN_RUNNING
+# define RT_WITH_W64_UNWIND_HACK
+#endif
+/** @def UNWIND_WRAP
+ * If RT_WITH_W64_UNWIND_HACK is defined, the name will be prefixed with
+ * 'supdrvNtWrap'.
+ * @param Name The function to wrapper. */
+#ifdef RT_WITH_W64_UNWIND_HACK
+# define UNWIND_WRAP(Name) supdrvNtWrap##Name
+#else
+# define UNWIND_WRAP(Name) Name
+#endif
+
+
+/*
+ * Error codes.
+ */
+/** @todo retire the SUPDRV_ERR_* stuff, we ship err.h now. */
+/** Invalid parameter. */
+#define SUPDRV_ERR_GENERAL_FAILURE (-1)
+/** Invalid parameter. */
+#define SUPDRV_ERR_INVALID_PARAM (-2)
+/** Invalid magic or cookie. */
+#define SUPDRV_ERR_INVALID_MAGIC (-3)
+/** Invalid loader handle. */
+#define SUPDRV_ERR_INVALID_HANDLE (-4)
+/** Failed to lock the address range. */
+#define SUPDRV_ERR_LOCK_FAILED (-5)
+/** Invalid memory pointer. */
+#define SUPDRV_ERR_INVALID_POINTER (-6)
+/** Failed to patch the IDT. */
+#define SUPDRV_ERR_IDT_FAILED (-7)
+/** Memory allocation failed. */
+#define SUPDRV_ERR_NO_MEMORY (-8)
+/** Already loaded. */
+#define SUPDRV_ERR_ALREADY_LOADED (-9)
+/** Permission denied. */
+#define SUPDRV_ERR_PERMISSION_DENIED (-10)
+/** Version mismatch. */
+#define SUPDRV_ERR_VERSION_MISMATCH (-11)
+
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** Pointer to the device extension. */
+typedef struct SUPDRVDEVEXT *PSUPDRVDEVEXT;
+
+
+/**
+ * Memory reference types.
+ */
+typedef enum
+{
+ /** Unused entry */
+ MEMREF_TYPE_UNUSED = 0,
+ /** Locked memory (r3 mapping only). */
+ MEMREF_TYPE_LOCKED,
+ /** Continous memory block (r3 and r0 mapping). */
+ MEMREF_TYPE_CONT,
+ /** Low memory block (r3 and r0 mapping). */
+ MEMREF_TYPE_LOW,
+ /** Memory block (r3 and r0 mapping). */
+ MEMREF_TYPE_MEM,
+ /** Locked memory (r3 mapping only) allocated by the support driver. */
+ MEMREF_TYPE_PAGE,
+ /** Blow the type up to 32-bit and mark the end. */
+ MEMREG_TYPE_32BIT_HACK = 0x7fffffff
+} SUPDRVMEMREFTYPE, *PSUPDRVMEMREFTYPE;
+
+
+/**
+ * Structure used for tracking memory a session
+ * references in one way or another.
+ */
+typedef struct SUPDRVMEMREF
+{
+ /** The memory object handle. */
+ RTR0MEMOBJ MemObj;
+ /** The ring-3 mapping memory object handle. */
+ RTR0MEMOBJ MapObjR3;
+ /** Type of memory. */
+ SUPDRVMEMREFTYPE eType;
+} SUPDRVMEMREF, *PSUPDRVMEMREF;
+
+
+/**
+ * Bundle of locked memory ranges.
+ */
+typedef struct SUPDRVBUNDLE
+{
+ /** Pointer to the next bundle. */
+ struct SUPDRVBUNDLE * volatile pNext;
+ /** Referenced memory. */
+ SUPDRVMEMREF aMem[64];
+ /** Number of entries used. */
+ uint32_t volatile cUsed;
+} SUPDRVBUNDLE, *PSUPDRVBUNDLE;
+
+
+/**
+ * Loaded image.
+ */
+typedef struct SUPDRVLDRIMAGE
+{
+ /** Next in chain. */
+ struct SUPDRVLDRIMAGE * volatile pNext;
+ /** Pointer to the image. */
+ void *pvImage;
+ /** Pointer to the optional module initialization callback. */
+ PFNR0MODULEINIT pfnModuleInit;
+ /** Pointer to the optional module termination callback. */
+ PFNR0MODULETERM pfnModuleTerm;
+ /** Service request handler. This is NULL for non-service modules. */
+ PFNSUPR0SERVICEREQHANDLER pfnServiceReqHandler;
+ /** Size of the image. */
+ uint32_t cbImage;
+ /** The offset of the symbol table. */
+ uint32_t offSymbols;
+ /** The number of entries in the symbol table. */
+ uint32_t cSymbols;
+ /** The offset of the string table. */
+ uint32_t offStrTab;
+ /** Size of the string table. */
+ uint32_t cbStrTab;
+ /** The ldr image state. (IOCtl code of last opration.) */
+ uint32_t uState;
+ /** Usage count. */
+ uint32_t volatile cUsage;
+ /** Image name. */
+ char szName[32];
+} SUPDRVLDRIMAGE, *PSUPDRVLDRIMAGE;
+
+
+/** Image usage record. */
+typedef struct SUPDRVLDRUSAGE
+{
+ /** Next in chain. */
+ struct SUPDRVLDRUSAGE * volatile pNext;
+ /** The image. */
+ PSUPDRVLDRIMAGE pImage;
+ /** Load count. */
+ uint32_t volatile cUsage;
+} SUPDRVLDRUSAGE, *PSUPDRVLDRUSAGE;
+
+
+/**
+ * Component factory registration record.
+ */
+typedef struct SUPDRVFACTORYREG
+{
+ /** Pointer to the next registration. */
+ struct SUPDRVFACTORYREG *pNext;
+ /** Pointer to the registered factory. */
+ PCSUPDRVFACTORY pFactory;
+ /** The session owning the factory.
+ * Used for deregistration and session cleanup. */
+ PSUPDRVSESSION pSession;
+ /** Length of the name. */
+ size_t cchName;
+} SUPDRVFACTORYREG;
+/** Pointer to a component factory registration record. */
+typedef SUPDRVFACTORYREG *PSUPDRVFACTORYREG;
+/** Pointer to a const component factory registration record. */
+typedef SUPDRVFACTORYREG const *PCSUPDRVFACTORYREG;
+
+
+/**
+ * Registered object.
+ * This takes care of reference counting and tracking data for access checks.
+ */
+typedef struct SUPDRVOBJ
+{
+ /** Magic value (SUPDRVOBJ_MAGIC). */
+ uint32_t u32Magic;
+ /** The object type. */
+ SUPDRVOBJTYPE enmType;
+ /** Pointer to the next in the global list. */
+ struct SUPDRVOBJ * volatile pNext;
+ /** Pointer to the object destructor.
+ * This may be set to NULL if the image containing the destructor get unloaded. */
+ PFNSUPDRVDESTRUCTOR pfnDestructor;
+ /** User argument 1. */
+ void *pvUser1;
+ /** User argument 2. */
+ void *pvUser2;
+ /** The total sum of all per-session usage. */
+ uint32_t volatile cUsage;
+ /** The creator user id. */
+ RTUID CreatorUid;
+ /** The creator group id. */
+ RTGID CreatorGid;
+ /** The creator process id. */
+ RTPROCESS CreatorProcess;
+} SUPDRVOBJ, *PSUPDRVOBJ;
+
+/** Magic number for SUPDRVOBJ::u32Magic. (Dame Agatha Mary Clarissa Christie). */
+#define SUPDRVOBJ_MAGIC 0x18900915
+/** Dead number magic for SUPDRVOBJ::u32Magic. */
+#define SUPDRVOBJ_MAGIC_DEAD 0x19760112
+
+/**
+ * The per-session object usage record.
+ */
+typedef struct SUPDRVUSAGE
+{
+ /** Pointer to the next in the list. */
+ struct SUPDRVUSAGE * volatile pNext;
+ /** Pointer to the object we're recording usage for. */
+ PSUPDRVOBJ pObj;
+ /** The usage count. */
+ uint32_t volatile cUsage;
+} SUPDRVUSAGE, *PSUPDRVUSAGE;
+
+
+/**
+ * Per session data.
+ * This is mainly for memory tracking.
+ */
+typedef struct SUPDRVSESSION
+{
+ /** Pointer to the device extension. */
+ PSUPDRVDEVEXT pDevExt;
+ /** Session Cookie. */
+ uint32_t u32Cookie;
+
+ /** Load usage records. (protected by SUPDRVDEVEXT::mtxLdr) */
+ PSUPDRVLDRUSAGE volatile pLdrUsage;
+ /** The VM associated with the session. */
+ PVM pVM;
+ /** List of generic usage records. (protected by SUPDRVDEVEXT::SpinLock) */
+ PSUPDRVUSAGE volatile pUsage;
+
+ /** Spinlock protecting the bundles and the GIP members. */
+ RTSPINLOCK Spinlock;
+ /** The ring-3 mapping of the GIP (readonly). */
+ RTR0MEMOBJ GipMapObjR3;
+ /** Set if the session is using the GIP. */
+ uint32_t fGipReferenced;
+ /** Bundle of locked memory objects. */
+ SUPDRVBUNDLE Bundle;
+
+ /** The user id of the session. (Set by the OS part.) */
+ RTUID Uid;
+ /** The group id of the session. (Set by the OS part.) */
+ RTGID Gid;
+ /** The process (id) of the session. */
+ RTPROCESS Process;
+ /** Which process this session is associated with.
+ * This is NIL_RTR0PROCESS for kernel sessions and valid for user ones. */
+ RTR0PROCESS R0Process;
+#if defined(RT_OS_DARWIN)
+ /** Pointer to the associated org_virtualbox_SupDrvClient object. */
+ void *pvSupDrvClient;
+ /** Whether this session has been opened or not. */
+ bool fOpened;
+#endif
+#if defined(RT_OS_OS2)
+ /** The system file number of this session. */
+ uint16_t sfn;
+ uint16_t Alignment; /**< Alignment */
+#endif
+#if defined(RT_OS_DARWIN) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS)
+ /** Pointer to the next session with the same hash. */
+ PSUPDRVSESSION pNextHash;
+#endif
+} SUPDRVSESSION;
+
+
+/**
+ * Device extension.
+ */
+typedef struct SUPDRVDEVEXT
+{
+ /** Spinlock to serialize the initialization,
+ * usage counting and destruction of the IDT entry override and objects. */
+ RTSPINLOCK Spinlock;
+
+ /** List of registered objects. Protected by the spinlock. */
+ PSUPDRVOBJ volatile pObjs;
+ /** List of free object usage records. */
+ PSUPDRVUSAGE volatile pUsageFree;
+
+ /** Global cookie. */
+ uint32_t u32Cookie;
+
+ /** The IDT entry number.
+ * Only valid if pIdtPatches is set. */
+ uint8_t volatile u8Idt;
+
+ /** Loader mutex.
+ * This protects pvVMMR0, pvVMMR0Entry, pImages and SUPDRVSESSION::pLdrUsage. */
+ RTSEMFASTMUTEX mtxLdr;
+
+ /** VMM Module 'handle'.
+ * 0 if the code VMM isn't loaded and Idt are nops. */
+ void * volatile pvVMMR0;
+ /** VMMR0EntryInt() pointer. */
+ DECLR0CALLBACKMEMBER(int, pfnVMMR0EntryInt, (PVM pVM, unsigned uOperation, void *pvArg));
+ /** VMMR0EntryFast() pointer. */
+ DECLR0CALLBACKMEMBER(void, pfnVMMR0EntryFast, (PVM pVM, unsigned idCpu, unsigned uOperation));
+ /** VMMR0EntryEx() pointer. */
+ DECLR0CALLBACKMEMBER(int, pfnVMMR0EntryEx, (PVM pVM, unsigned uOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession));
+
+ /** Linked list of loaded code. */
+ PSUPDRVLDRIMAGE volatile pLdrImages;
+
+ /** GIP mutex.
+ * Any changes to any of the GIP members requires ownership of this mutex,
+ * except on driver init and termination. */
+ RTSEMFASTMUTEX mtxGip;
+ /** Pointer to the Global Info Page (GIP). */
+ PSUPGLOBALINFOPAGE pGip;
+ /** The physical address of the GIP. */
+ RTHCPHYS HCPhysGip;
+ /** Number of processes using the GIP.
+ * (The updates are suspend while cGipUsers is 0.)*/
+ uint32_t volatile cGipUsers;
+ /** The ring-0 memory object handle for the GIP page. */
+ RTR0MEMOBJ GipMemObj;
+ /** The GIP timer handle. */
+ PRTTIMER pGipTimer;
+ /** If non-zero we've successfully called RTTimerRequestSystemGranularity(). */
+ uint32_t u32SystemTimerGranularityGrant;
+ /** The CPU id of the GIP master.
+ * This CPU is responsible for the updating the common GIP data. */
+ RTCPUID volatile idGipMaster;
+
+#ifdef RT_OS_WINDOWS
+ /* Callback object returned by ExCreateCallback. */
+ PCALLBACK_OBJECT pObjPowerCallback;
+ /* Callback handle returned by ExRegisterCallback. */
+ PVOID hPowerCallback;
+#endif
+
+ /** Component factory mutex.
+ * This protects pComponentFactoryHead and component factory querying. */
+ RTSEMFASTMUTEX mtxComponentFactory;
+ /** The head of the list of registered component factories. */
+ PSUPDRVFACTORYREG pComponentFactoryHead;
+} SUPDRVDEVEXT;
+
+
+__BEGIN_DECLS
+
+/*******************************************************************************
+* OS Specific Functions *
+*******************************************************************************/
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession);
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc);
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt);
+int VBOXCALL supdrvOSEnableVTx(bool fEnabled);
+
+/*******************************************************************************
+* Shared Functions *
+*******************************************************************************/
+int VBOXCALL supdrvIOCtl(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPREQHDR pReqHdr);
+int VBOXCALL supdrvIOCtlFast(uintptr_t uIOCtl, unsigned idCpu, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession);
+int VBOXCALL supdrvIDC(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVIDCREQHDR pReqHdr);
+int VBOXCALL supdrvInitDevExt(PSUPDRVDEVEXT pDevExt);
+void VBOXCALL supdrvDeleteDevExt(PSUPDRVDEVEXT pDevExt);
+int VBOXCALL supdrvCreateSession(PSUPDRVDEVEXT pDevExt, bool fUser, PSUPDRVSESSION *ppSession);
+void VBOXCALL supdrvCloseSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession);
+void VBOXCALL supdrvCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession);
+int VBOXCALL supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys, uint64_t u64NanoTS, unsigned uUpdateHz);
+void VBOXCALL supdrvGipTerm(PSUPGLOBALINFOPAGE pGip);
+void VBOXCALL supdrvGipUpdate(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS);
+void VBOXCALL supdrvGipUpdatePerCpu(PSUPGLOBALINFOPAGE pGip, uint64_t u64NanoTS, unsigned iCpu);
+bool VBOXCALL supdrvDetermineAsyncTsc(uint64_t *pu64DiffCores);
+
+__END_DECLS
+
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
new file mode 100644
index 000000000..ed3db1125
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -0,0 +1,1928 @@
+/* $Id: SUPLib.cpp 15841 2009-01-07 16:40:02Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Common code.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/** @page pg_sup SUP - The Support Library
+ *
+ * The support library is responsible for providing facilities to load
+ * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
+ * code, to pin down physical memory, and more.
+ *
+ * The VMM Host Ring-0 code can be combined in the support driver if
+ * permitted by kernel module license policies. If it is not combined
+ * it will be externalized in a .r0 module that will be loaded using
+ * the IPRT loader.
+ *
+ * The Ring-0 calling is done thru a generic SUP interface which will
+ * tranfer an argument set and call a predefined entry point in the Host
+ * VMM Ring-0 code.
+ *
+ * See @ref grp_sup "SUP - Support APIs" for API details.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <VBox/vmm.h>
+#include <VBox/log.h>
+#include <VBox/x86.h>
+
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/ldr.h>
+#include <iprt/asm.h>
+#include <iprt/mp.h>
+#include <iprt/cpuset.h>
+#include <iprt/thread.h>
+#include <iprt/process.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/env.h>
+#include <iprt/rand.h>
+
+#include "SUPLibInternal.h"
+#include "SUPDrvIOC.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** R0 VMM module name. */
+#define VMMR0_NAME "VMMR0"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+typedef DECLCALLBACK(int) FNCALLVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg);
+typedef FNCALLVMMR0 *PFNCALLVMMR0;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Init counter. */
+static uint32_t g_cInits = 0;
+/** Whether we've been preinitied. */
+static bool g_fPreInited = false;
+/** The SUPLib instance data.
+ * Well, at least parts of it, specificly the parts that are being handed over
+ * via the pre-init mechanism from the hardened executable stub. */
+static SUPLIBDATA g_supLibData =
+{
+ NIL_RTFILE
+#if defined(RT_OS_DARWIN)
+ , NULL
+#elif defined(RT_OS_LINUX)
+ , false
+#endif
+};
+
+/** Pointer to the Global Information Page.
+ *
+ * This pointer is valid as long as SUPLib has a open session. Anyone using
+ * the page must treat this pointer as higly volatile and not trust it beyond
+ * one transaction.
+ *
+ * @todo This will probably deserve it's own session or some other good solution...
+ */
+DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
+/** Address of the ring-0 mapping of the GIP. */
+static PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
+/** The physical address of the GIP. */
+static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
+
+/** The negotiated cookie. */
+uint32_t g_u32Cookie = 0;
+/** The negotiated session cookie. */
+uint32_t g_u32SessionCookie;
+/** Session handle. */
+PSUPDRVSESSION g_pSession;
+/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
+static PSUPQUERYFUNCS g_pFunctions;
+
+/** VMMR0 Load Address. */
+static RTR0PTR g_pvVMMR0 = NIL_RTR0PTR;
+/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
+static bool g_fSupportsPageAllocNoKernel = true;
+/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
+static uint32_t g_u32FakeMode = ~0;
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int supInitFake(PSUPDRVSESSION *ppSession);
+static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase);
+static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
+
+
+SUPR3DECL(int) SUPInstall(void)
+{
+ return suplibOsInstall();
+}
+
+
+SUPR3DECL(int) SUPUninstall(void)
+{
+ return suplibOsUninstall();
+}
+
+
+DECLEXPORT(int) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
+{
+ /*
+ * The caller is kind of trustworthy, just perform some basic checks.
+ *
+ * Note! Do not do any fancy stuff here because IPRT has NOT been
+ * initialized at this point.
+ */
+ if (!VALID_PTR(pPreInitData))
+ return VERR_INVALID_POINTER;
+ if (g_fPreInited || g_cInits > 0)
+ return VERR_WRONG_ORDER;
+
+ if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
+ || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
+ return VERR_INVALID_MAGIC;
+ if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+ && pPreInitData->Data.hDevice == NIL_RTFILE)
+ return VERR_INVALID_HANDLE;
+ if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
+ && pPreInitData->Data.hDevice != NIL_RTFILE)
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Hand out the data.
+ */
+ int rc = supR3HardenedRecvPreInitData(pPreInitData);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
+ if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
+ {
+ g_supLibData = pPreInitData->Data;
+ g_fPreInited = true;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
+{
+ /*
+ * Perform some sanity checks.
+ * (Got some trouble with compile time member alignment assertions.)
+ */
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
+ Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
+
+ /*
+ * Check if already initialized.
+ */
+ if (ppSession)
+ *ppSession = g_pSession;
+ if (g_cInits++ > 0)
+ return VINF_SUCCESS;
+
+ /*
+ * Check for fake mode.
+ *
+ * Fake mode is used when we're doing smoke testing and debugging.
+ * It's also useful on platforms where we haven't root access or which
+ * we haven't ported the support driver to.
+ */
+ if (g_u32FakeMode == ~0U)
+ {
+ const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
+ if (psz && !strcmp(psz, "fake"))
+ ASMAtomicCmpXchgU32(&g_u32FakeMode, 1, ~0U);
+ else
+ ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
+ }
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return supInitFake(ppSession);
+
+ /*
+ * Open the support driver.
+ */
+ int rc = suplibOsInit(&g_supLibData, g_fPreInited);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Negotiate the cookie.
+ */
+ SUPCOOKIE CookieReq;
+ memset(&CookieReq, 0xff, sizeof(CookieReq));
+ CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
+ CookieReq.Hdr.u32SessionCookie = RTRandU32();
+ CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
+ CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
+ CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
+ CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
+ const uint32_t MinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x000a0000
+ ? 0x000a0009
+ : SUPDRV_IOC_VERSION & 0xffff0000;
+ CookieReq.u.In.u32MinVersion = MinVersion;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(CookieReq.Hdr.rc))
+ {
+ if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
+ && CookieReq.u.Out.u32SessionVersion >= MinVersion)
+ {
+ /*
+ * Query the functions.
+ */
+ PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
+ if (pFuncsReq)
+ {
+ pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
+ pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
+ pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
+ pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
+ pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
+ if (RT_SUCCESS(rc))
+ rc = pFuncsReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ g_u32Cookie = CookieReq.u.Out.u32Cookie;
+ g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
+ g_pSession = CookieReq.u.Out.pSession;
+ g_pFunctions = pFuncsReq;
+ if (ppSession)
+ *ppSession = CookieReq.u.Out.pSession;
+
+ /*
+ * Map the GIP into userspace.
+ * This is an optional feature, so we will ignore any failures here.
+ */
+ if (!g_pSUPGlobalInfoPage)
+ {
+ SUPGIPMAP GipMapReq;
+ GipMapReq.Hdr.u32Cookie = g_u32Cookie;
+ GipMapReq.Hdr.u32SessionCookie = g_u32SessionCookie;
+ GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
+ GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
+ GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
+ GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
+ GipMapReq.u.Out.pGipR3 = NULL;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = GipMapReq.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
+ AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
+ ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
+ }
+ }
+ return VINF_SUCCESS;
+ }
+
+ /* bailout */
+ RTMemFree(pFuncsReq);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ {
+ LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
+ CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, MinVersion));
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ }
+ else
+ {
+ if (RT_SUCCESS(rc))
+ {
+ rc = CookieReq.Hdr.rc;
+ LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
+ CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
+ if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ else
+ {
+ /* for pre 0x00060000 drivers */
+ LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
+ rc = VERR_VM_DRIVER_VERSION_MISMATCH;
+ }
+ }
+
+ suplibOsTerm(&g_supLibData);
+ }
+ AssertMsgFailed(("SUPR3Init() failed rc=%Rrc\n", rc));
+ g_cInits--;
+
+ return rc;
+}
+
+/**
+ * Fake mode init.
+ */
+static int supInitFake(PSUPDRVSESSION *ppSession)
+{
+ Log(("SUP: Fake mode!\n"));
+ static const SUPFUNC s_aFakeFunctions[] =
+ {
+ /* name function */
+ { "SUPR0AbsIs64bit", 0 },
+ { "SUPR0Abs64bitKernelCS", 0 },
+ { "SUPR0Abs64bitKernelSS", 0 },
+ { "SUPR0Abs64bitKernelDS", 0 },
+ { "SUPR0AbsKernelCS", 8 },
+ { "SUPR0AbsKernelSS", 16 },
+ { "SUPR0AbsKernelDS", 16 },
+ { "SUPR0AbsKernelES", 16 },
+ { "SUPR0AbsKernelFS", 24 },
+ { "SUPR0AbsKernelGS", 32 },
+ { "SUPR0ComponentRegisterFactory", 0xefeefffd },
+ { "SUPR0ComponentDeregisterFactory", 0xefeefffe },
+ { "SUPR0ComponentQueryFactory", 0xefeeffff },
+ { "SUPR0ObjRegister", 0xefef0000 },
+ { "SUPR0ObjAddRef", 0xefef0001 },
+ { "SUPR0ObjAddRefEx", 0xefef0001 },
+ { "SUPR0ObjRelease", 0xefef0002 },
+ { "SUPR0ObjVerifyAccess", 0xefef0003 },
+ { "SUPR0LockMem", 0xefef0004 },
+ { "SUPR0UnlockMem", 0xefef0005 },
+ { "SUPR0ContAlloc", 0xefef0006 },
+ { "SUPR0ContFree", 0xefef0007 },
+ { "SUPR0MemAlloc", 0xefef0008 },
+ { "SUPR0MemGetPhys", 0xefef0009 },
+ { "SUPR0MemFree", 0xefef000a },
+ { "SUPR0Printf", 0xefef000b },
+ { "SUPR0GetPagingMode", 0xefef000c },
+ { "SUPR0EnableVTx", 0xefef000c },
+ { "RTMemAlloc", 0xefef000d },
+ { "RTMemAllocZ", 0xefef000e },
+ { "RTMemFree", 0xefef000f },
+ { "RTR0MemObjAddress", 0xefef0010 },
+ { "RTR0MemObjAddressR3", 0xefef0011 },
+ { "RTR0MemObjAllocPage", 0xefef0012 },
+ { "RTR0MemObjAllocPhysNC", 0xefef0013 },
+ { "RTR0MemObjAllocLow", 0xefef0014 },
+ { "RTR0MemObjEnterPhys", 0xefef0014 },
+ { "RTR0MemObjFree", 0xefef0015 },
+ { "RTR0MemObjGetPagePhysAddr", 0xefef0016 },
+ { "RTR0MemObjMapUser", 0xefef0017 },
+ { "RTR0MemObjMapKernel", 0xefef0017 },
+ { "RTR0MemObjMapKernelEx", 0xefef0017 },
+ { "RTProcSelf", 0xefef0038 },
+ { "RTR0ProcHandleSelf", 0xefef0039 },
+ { "RTSemEventCreate", 0xefef0018 },
+ { "RTSemEventSignal", 0xefef0019 },
+ { "RTSemEventWait", 0xefef001a },
+ { "RTSemEventWaitNoResume", 0xefef001b },
+ { "RTSemEventDestroy", 0xefef001c },
+ { "RTSemEventMultiCreate", 0xefef001d },
+ { "RTSemEventMultiSignal", 0xefef001e },
+ { "RTSemEventMultiReset", 0xefef001f },
+ { "RTSemEventMultiWait", 0xefef0020 },
+ { "RTSemEventMultiWaitNoResume", 0xefef0021 },
+ { "RTSemEventMultiDestroy", 0xefef0022 },
+ { "RTSemFastMutexCreate", 0xefef0023 },
+ { "RTSemFastMutexDestroy", 0xefef0024 },
+ { "RTSemFastMutexRequest", 0xefef0025 },
+ { "RTSemFastMutexRelease", 0xefef0026 },
+ { "RTSpinlockCreate", 0xefef0027 },
+ { "RTSpinlockDestroy", 0xefef0028 },
+ { "RTSpinlockAcquire", 0xefef0029 },
+ { "RTSpinlockRelease", 0xefef002a },
+ { "RTSpinlockAcquireNoInts", 0xefef002b },
+ { "RTSpinlockReleaseNoInts", 0xefef002c },
+ { "RTTimeNanoTS", 0xefef002d },
+ { "RTTimeMillieTS", 0xefef002e },
+ { "RTTimeSystemNanoTS", 0xefef002f },
+ { "RTTimeSystemMillieTS", 0xefef0030 },
+ { "RTThreadNativeSelf", 0xefef0031 },
+ { "RTThreadSleep", 0xefef0032 },
+ { "RTThreadYield", 0xefef0033 },
+ { "RTLogDefaultInstance", 0xefef0034 },
+ { "RTLogRelDefaultInstance", 0xefef0035 },
+ { "RTLogSetDefaultInstanceThread", 0xefef0036 },
+ { "RTLogLogger", 0xefef0037 },
+ { "RTLogLoggerEx", 0xefef0038 },
+ { "RTLogLoggerExV", 0xefef0039 },
+ { "AssertMsg1", 0xefef003a },
+ { "AssertMsg2", 0xefef003b },
+ { "RTAssertMsg1", 0xefef003c },
+ { "RTAssertMsg2", 0xefef003d },
+ { "RTAssertMsg2V", 0xefef003e },
+ };
+
+ /* fake r0 functions. */
+ g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
+ if (g_pFunctions)
+ {
+ g_pFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
+ memcpy(&g_pFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
+ g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
+ if (ppSession)
+ *ppSession = g_pSession;
+
+ /* fake the GIP. */
+ g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
+ if (g_pSUPGlobalInfoPage)
+ {
+ g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
+ g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
+ /* the page is supposed to be invalid, so don't set the magic. */
+ return VINF_SUCCESS;
+ }
+
+ RTMemFree(g_pFunctions);
+ g_pFunctions = NULL;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+SUPR3DECL(int) SUPTerm(bool fForced)
+{
+ /*
+ * Verify state.
+ */
+ AssertMsg(g_cInits > 0, ("SUPTerm() is called before SUPR3Init()!\n"));
+ if (g_cInits == 0)
+ return VERR_WRONG_ORDER;
+ if (g_cInits == 1 || fForced)
+ {
+ /*
+ * NULL the GIP pointer.
+ */
+ if (g_pSUPGlobalInfoPage)
+ {
+ ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, NULL);
+ ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, NULL);
+ ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
+ /* just a little safe guard against threads using the page. */
+ RTThreadSleep(50);
+ }
+
+ /*
+ * Close the support driver.
+ */
+ int rc = suplibOsTerm(&g_supLibData);
+ if (rc)
+ return rc;
+
+ g_u32Cookie = 0;
+ g_u32SessionCookie = 0;
+ g_cInits = 0;
+ }
+ else
+ g_cInits--;
+
+ return 0;
+}
+
+
+SUPR3DECL(SUPPAGINGMODE) SUPGetPagingMode(void)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+#ifdef RT_ARCH_AMD64
+ return SUPPAGINGMODE_AMD64_GLOBAL_NX;
+#else
+ return SUPPAGINGMODE_32_BIT_GLOBAL;
+#endif
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPGETPAGINGMODE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
+ if ( RT_FAILURE(rc)
+ || RT_FAILURE(Req.Hdr.rc))
+ {
+ LogRel(("SUPGetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
+ Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
+ }
+
+ return Req.u.Out.enmMode;
+}
+
+
+/**
+ * For later.
+ */
+static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ AssertMsgFailed(("%d\n", uOperation));
+ return VERR_NOT_SUPPORTED;
+}
+
+
+SUPR3DECL(int) SUPCallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, unsigned idCpu)
+{
+ if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
+ return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_RAW_RUN, idCpu);
+ if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
+ return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_HWACC_RUN, idCpu);
+ if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
+ return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_NOP, idCpu);
+
+ AssertMsgFailed(("%#x\n", uOperation));
+ return VERR_INTERNAL_ERROR;
+}
+
+
+SUPR3DECL(int) SUPCallVMMR0Ex(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ /*
+ * The following operations don't belong here.
+ */
+ AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
+ && uOperation != SUP_VMMR0_DO_HWACC_RUN
+ && uOperation != SUP_VMMR0_DO_NOP,
+ ("%#x\n", uOperation),
+ VERR_INTERNAL_ERROR);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
+
+ int rc;
+ if (!pReqHdr)
+ {
+ /* no data. */
+ SUPCALLVMMR0 Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
+ Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pVMR0 = pVMR0;
+ Req.u.In.uOperation = uOperation;
+ Req.u.In.u64Arg = u64Arg;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ }
+ else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
+ {
+ AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
+ AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
+ const size_t cbReq = pReqHdr->cbReq;
+
+ PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
+ pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.pVMR0 = pVMR0;
+ pReq->u.In.uOperation = uOperation;
+ pReq->u.In.u64Arg = u64Arg;
+ memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
+ }
+ else /** @todo may have to remove the size limits one this request... */
+ AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPCallVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg)
+{
+ /*
+ * The following operations don't belong here.
+ */
+ AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
+ && uOperation != SUP_VMMR0_DO_HWACC_RUN
+ && uOperation != SUP_VMMR0_DO_NOP,
+ ("%#x\n", uOperation),
+ VERR_INTERNAL_ERROR);
+ return SUPCallVMMR0Ex(pVMR0, uOperation, (uintptr_t)pvArg, NULL);
+}
+
+
+SUPR3DECL(int) SUPSetVMForFastIOCtl(PVMR0 pVMR0)
+{
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return VINF_SUCCESS;
+
+ SUPSETVMFORFAST Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pVMR0 = pVMR0;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
+{
+ AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
+ Assert(strlen(pszService) == cchService);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return VERR_NOT_SUPPORTED;
+
+ int rc;
+ if (!pReqHdr)
+ {
+ /* no data. */
+ SUPCALLSERVICE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
+ Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ memcpy(Req.u.In.szName, pszService, cchService);
+ Req.u.In.szName[cchService] = '\0';
+ Req.u.In.uOperation = uOperation;
+ Req.u.In.u64Arg = u64Arg;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ }
+ else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
+ {
+ AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
+ AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
+ const size_t cbReq = pReqHdr->cbReq;
+
+ PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
+ pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ memcpy(pReq->u.In.szName, pszService, cchService);
+ pReq->u.In.szName[cchService] = '\0';
+ pReq->u.In.uOperation = uOperation;
+ pReq->u.In.u64Arg = u64Arg;
+ memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
+ }
+ else /** @todo may have to remove the size limits one this request... */
+ AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPPageAlloc(size_t cPages, void **ppvPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * Temporary hack for windows until we've sorted out the
+ * locked memory that doesn't need to be accessible from kernel space.
+ */
+ return SUPPageAllocLockedEx(cPages, ppvPages, NULL);
+#else
+ /*
+ * Call OS specific worker.
+ */
+ return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
+#endif
+}
+
+
+SUPR3DECL(int) SUPPageFree(void *pvPages, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * Temporary hack for windows, see above.
+ */
+ return SUPPageFreeLocked(pvPages, cPages);
+#else
+ /*
+ * Call OS specific worker.
+ */
+ return suplibOsPageFree(&g_supLibData, pvPages, cPages);
+#endif
+}
+
+
+SUPR3DECL(int) SUPPageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtr(pvStart);
+ AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
+ AssertPtr(paPages);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
+ if (RT_LIKELY(pReq))
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.pvR3 = pvStart;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ for (uint32_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+ }
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPPageUnlock(void *pvStart)
+{
+ /*
+ * Validate.
+ */
+ AssertPtr(pvStart);
+ AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return VINF_SUCCESS;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPPAGEUNLOCK Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvStart;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPPageAllocLockedEx(size_t cPages, void **ppvPages, PSUPPAGE paPages)
+{
+ return SUPR3PageAllocEx(cPages, 0 /*fFlags*/, ppvPages, NULL /*pR0Ptr*/, paPages);
+}
+
+
+SUPR3DECL(int) SUPPageFreeLocked(void *pvPages, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /*
+ * Check if we're employing the fallback or not to avoid the
+ * fuzzy handling of this in SUPR3PageFreeEx.
+ */
+ int rc;
+ if (g_fSupportsPageAllocNoKernel)
+ rc = SUPR3PageFreeEx(pvPages, cPages);
+ else
+ {
+ /* fallback */
+ rc = SUPPageUnlock(pvPages);
+ if (RT_SUCCESS(rc))
+ rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
+ }
+ return rc;
+}
+
+
+/**
+ * Fallback for SUPPageAllocLockedEx on systems where RTR0MemObjPhysAllocNC isn't supported.
+ */
+static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
+{
+ int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
+ if (RT_SUCCESS(rc))
+ {
+ if (!paPages)
+ paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
+ rc = SUPPageLock(*ppvPages, cPages, paPages);
+ if (RT_FAILURE(rc))
+ suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
+ }
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
+ if (pR0Ptr)
+ *pR0Ptr = NIL_RTR0PTR;
+ AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
+ AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
+ if (!pv)
+ return VERR_NO_MEMORY;
+ *ppvPages = pv;
+ if (pR0Ptr)
+ *pR0Ptr = (RTR0PTR)pv;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = (iPage + 4321) << PAGE_SHIFT;
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Use fallback for non-R0 mapping?
+ */
+ if ( !pR0Ptr
+ && !g_fSupportsPageAllocNoKernel)
+ return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
+ if (pReq)
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ pReq->u.In.fKernelMapping = pR0Ptr != NULL;
+ pReq->u.In.fUserMapping = true;
+ pReq->u.In.fReserved0 = false;
+ pReq->u.In.fReserved1 = false;
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ {
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *ppvPages = pReq->u.Out.pvR3;
+ if (pR0Ptr)
+ *pR0Ptr = pReq->u.Out.pvR0;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ }
+ }
+ else if ( rc == VERR_NOT_SUPPORTED
+ && !pR0Ptr)
+ {
+ g_fSupportsPageAllocNoKernel = false;
+ rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
+ }
+ }
+
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+ return rc;
+
+}
+
+
+SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
+ AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
+ Assert(!(off & PAGE_OFFSET_MASK));
+ Assert(!(cb & PAGE_OFFSET_MASK) && cb);
+ Assert(!fFlags);
+ *pR0Ptr = NIL_RTR0PTR;
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPPAGEMAPKERNEL Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvR3;
+ Req.u.In.offSub = off;
+ Req.u.In.cbSub = cb;
+ Req.u.In.fFlags = fFlags;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *pR0Ptr = Req.u.Out.pvR0;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ RTMemPageFree(pvPages);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Try normal free first, then if it fails check if we're using the fallback .
+ * for the allocations without kernel mappings and attempt unlocking it.
+ */
+ NOREF(cPages);
+ SUPPAGEFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pvPages;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Req.Hdr.rc;
+ if ( rc == VERR_INVALID_PARAMETER
+ && !g_fSupportsPageAllocNoKernel)
+ {
+ int rc2 = SUPPageUnlock(pvPages);
+ if (RT_SUCCESS(rc2))
+ rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
+ }
+ }
+ return rc;
+}
+
+
+SUPR3DECL(void *) SUPContAlloc(size_t cPages, PRTHCPHYS pHCPhys)
+{
+ return SUPContAlloc2(cPages, NIL_RTR0PTR, pHCPhys);
+}
+
+
+SUPR3DECL(void *) SUPContAlloc2(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(pHCPhys, NULL);
+ *pHCPhys = NIL_RTHCPHYS;
+ AssertPtrNullReturn(pR0Ptr, NULL);
+ if (pR0Ptr)
+ *pR0Ptr = NIL_RTR0PTR;
+ AssertPtrNullReturn(pHCPhys, NULL);
+ AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
+ if (pR0Ptr)
+ *pR0Ptr = (RTR0PTR)pv;
+ if (pHCPhys)
+ *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
+ return pv;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTALLOC Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.cPages = (uint32_t)cPages;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(Req.Hdr.rc))
+ {
+ *pHCPhys = Req.u.Out.HCPhys;
+ if (pR0Ptr)
+ *pR0Ptr = Req.u.Out.pvR0;
+ return Req.u.Out.pvR3;
+ }
+
+ return NULL;
+}
+
+
+SUPR3DECL(int) SUPContFree(void *pv, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ if (!pv)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pv, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ RTMemPageFree(pv);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pv;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPLowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
+{
+ /*
+ * Validate.
+ */
+ AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
+ *ppvPages = NULL;
+ AssertPtrReturn(paPages, VERR_INVALID_POINTER);
+ AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
+ if (!*ppvPages)
+ return VERR_NO_LOW_MEMORY;
+
+ /* fake physical addresses. */
+ RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ int rc;
+ PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
+ if (pReq)
+ {
+ pReq->Hdr.u32Cookie = g_u32Cookie;
+ pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
+ pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
+ pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
+ pReq->Hdr.rc = VERR_INTERNAL_ERROR;
+ pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
+ if (RT_SUCCESS(rc))
+ rc = pReq->Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *ppvPages = pReq->u.Out.pvR3;
+ if (ppvPagesR0)
+ *ppvPagesR0 = pReq->u.Out.pvR0;
+ if (paPages)
+ for (size_t iPage = 0; iPage < cPages; iPage++)
+ {
+ paPages[iPage].uReserved = 0;
+ paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
+ Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
+ Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
+ }
+ }
+ RTMemTmpFree(pReq);
+ }
+ else
+ rc = VERR_NO_TMP_MEMORY;
+
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPLowFree(void *pv, size_t cPages)
+{
+ /*
+ * Validate.
+ */
+ if (!pv)
+ return VINF_SUCCESS;
+ AssertPtrReturn(pv, VERR_INVALID_POINTER);
+ AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ RTMemPageFree(pv);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Issue IOCtl to the SUPDRV kernel module.
+ */
+ SUPCONTFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvR3 = pv;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
+{
+ /*
+ * Quick input validation.
+ */
+ AssertPtr(pszFilename);
+ AssertPtr(pszMsg);
+ AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
+ file is the same we verified after opening it. */
+
+ /*
+ * Only do the actual check in hardened builds.
+ */
+#ifdef VBOX_WITH_HARDENING
+ int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
+ if (RT_FAILURE(rc))
+ LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
+ return rc;
+#else
+ return VINF_SUCCESS;
+#endif
+}
+
+
+SUPR3DECL(int) SUPLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
+{
+ int rc = VINF_SUCCESS;
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Check that the module can be trusted.
+ */
+ rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
+#endif
+ if (RT_SUCCESS(rc))
+ rc = supLoadModule(pszFilename, pszModule, NULL, ppvImageBase);
+ else
+ LogRel(("SUPLoadModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule,
+ const char *pszSrvReqHandler, void **ppvImageBase)
+{
+ int rc = VINF_SUCCESS;
+ AssertPtrReturn(pszSrvReqHandler, VERR_INVALID_PARAMETER);
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Check that the module can be trusted.
+ */
+ rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
+#endif
+ if (RT_SUCCESS(rc))
+ rc = supLoadModule(pszFilename, pszModule, pszSrvReqHandler, ppvImageBase);
+ else
+ LogRel(("SUPR3LoadServiceModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Resolve an external symbol during RTLdrGetBits().
+ *
+ * @returns VBox status code.
+ * @param hLdrMod The loader module handle.
+ * @param pszModule Module name.
+ * @param pszSymbol Symbol name, NULL if uSymbol should be used.
+ * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
+ * @param pValue Where to store the symbol value (address).
+ * @param pvUser User argument.
+ */
+static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
+ const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
+{
+ AssertPtr(pValue);
+ AssertPtr(pvUser);
+
+ /*
+ * Only SUPR0 and VMMR0.r0
+ */
+ if ( pszModule
+ && *pszModule
+ && strcmp(pszModule, "SUPR0.dll")
+ && strcmp(pszModule, "VMMR0.r0"))
+ {
+ AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
+ return VERR_SYMBOL_NOT_FOUND;
+ }
+
+ /*
+ * No ordinals.
+ */
+ if (pszSymbol < (const char*)0x10000)
+ {
+ AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
+ return VERR_SYMBOL_NOT_FOUND;
+ }
+
+ /*
+ * Lookup symbol.
+ */
+ /* skip the 64-bit ELF import prefix first. */
+ if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
+ pszSymbol += sizeof("SUPR0$") - 1;
+
+ /*
+ * Check the VMMR0.r0 module if loaded.
+ */
+ /** @todo call the SUPLoadModule caller.... */
+ /** @todo proper reference counting and such. */
+ if (g_pvVMMR0 != NIL_RTR0PTR)
+ {
+ void *pvValue;
+ if (!SUPGetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
+ {
+ *pValue = (uintptr_t)pvValue;
+ return VINF_SUCCESS;
+ }
+ }
+
+ /* iterate the function table. */
+ int c = g_pFunctions->u.Out.cFunctions;
+ PSUPFUNC pFunc = &g_pFunctions->u.Out.aFunctions[0];
+ while (c-- > 0)
+ {
+ if (!strcmp(pFunc->szName, pszSymbol))
+ {
+ *pValue = (uintptr_t)pFunc->pfn;
+ return VINF_SUCCESS;
+ }
+ pFunc++;
+ }
+
+ /*
+ * The GIP.
+ */
+ /** @todo R0 mapping? */
+ if ( pszSymbol
+ && g_pSUPGlobalInfoPage
+ && g_pSUPGlobalInfoPageR0
+ && !strcmp(pszSymbol, "g_SUPGlobalInfoPage"))
+ {
+ *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Despair.
+ */
+ c = g_pFunctions->u.Out.cFunctions;
+ pFunc = &g_pFunctions->u.Out.aFunctions[0];
+ while (c-- > 0)
+ {
+ AssertMsg2("%d: %s\n", g_pFunctions->u.Out.cFunctions - c, pFunc->szName);
+ pFunc++;
+ }
+
+ AssertMsg2("%s is importing %s which we couldn't find\n", pvUser, pszSymbol);
+ AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
+ if (g_u32FakeMode)
+ {
+ *pValue = 0xdeadbeef;
+ return VINF_SUCCESS;
+ }
+ return VERR_SYMBOL_NOT_FOUND;
+}
+
+
+/** Argument package for supLoadModuleCalcSizeCB. */
+typedef struct SUPLDRCALCSIZEARGS
+{
+ size_t cbStrings;
+ uint32_t cSymbols;
+ size_t cbImage;
+} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
+
+/**
+ * Callback used to calculate the image size.
+ * @return VINF_SUCCESS
+ */
+static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
+{
+ PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
+ if ( pszSymbol != NULL
+ && *pszSymbol
+ && Value <= pArgs->cbImage)
+ {
+ pArgs->cSymbols++;
+ pArgs->cbStrings += strlen(pszSymbol) + 1;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/** Argument package for supLoadModuleCreateTabsCB. */
+typedef struct SUPLDRCREATETABSARGS
+{
+ size_t cbImage;
+ PSUPLDRSYM pSym;
+ char *pszBase;
+ char *psz;
+} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
+
+/**
+ * Callback used to calculate the image size.
+ * @return VINF_SUCCESS
+ */
+static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
+{
+ PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
+ if ( pszSymbol != NULL
+ && *pszSymbol
+ && Value <= pArgs->cbImage)
+ {
+ pArgs->pSym->offSymbol = (uint32_t)Value;
+ pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
+ pArgs->pSym++;
+
+ size_t cbCopy = strlen(pszSymbol) + 1;
+ memcpy(pArgs->psz, pszSymbol, cbCopy);
+ pArgs->psz += cbCopy;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Worker for SUPLoadModule().
+ *
+ * @returns VBox status code.
+ * @param pszFilename Name of the VMMR0 image file
+ */
+static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
+ AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
+
+ const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
+ AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
+ *ppvImageBase = NULL;
+
+ /*
+ * Open image file and figure its size.
+ */
+ RTLDRMOD hLdrMod;
+ int rc = RTLdrOpen(pszFilename, &hLdrMod);
+ if (!RT_SUCCESS(rc))
+ return rc;
+
+ SUPLDRCALCSIZEARGS CalcArgs;
+ CalcArgs.cbStrings = 0;
+ CalcArgs.cSymbols = 0;
+ CalcArgs.cbImage = RTLdrSize(hLdrMod);
+ rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
+ if (RT_SUCCESS(rc))
+ {
+ const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
+ const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
+ const uint32_t cbImage = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
+
+ /*
+ * Open the R0 image.
+ */
+ SUPLDROPEN OpenReq;
+ OpenReq.Hdr.u32Cookie = g_u32Cookie;
+ OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
+ OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
+ OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
+ OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
+ OpenReq.u.In.cbImage = cbImage;
+ strcpy(OpenReq.u.In.szName, pszModule);
+ if (!g_u32FakeMode)
+ {
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = OpenReq.Hdr.rc;
+ }
+ else
+ {
+ OpenReq.u.Out.fNeedsLoading = true;
+ OpenReq.u.Out.pvImageBase = 0xef423420;
+ }
+ *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
+ if ( RT_SUCCESS(rc)
+ && OpenReq.u.Out.fNeedsLoading)
+ {
+ /*
+ * We need to load it.
+ * Allocate memory for the image bits.
+ */
+ PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
+ if (pLoadReq)
+ {
+ /*
+ * Get the image bits.
+ */
+ rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
+ supLoadModuleResolveImport, (void *)pszModule);
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the entry points.
+ */
+ RTUINTPTR VMMR0EntryInt = 0;
+ RTUINTPTR VMMR0EntryFast = 0;
+ RTUINTPTR VMMR0EntryEx = 0;
+ RTUINTPTR SrvReqHandler = 0;
+ RTUINTPTR ModuleInit = 0;
+ RTUINTPTR ModuleTerm = 0;
+ if (fIsVMMR0)
+ {
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
+ }
+ else if (pszSrvReqHandler)
+ rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
+ if (RT_FAILURE(rc2))
+ ModuleInit = 0;
+
+ rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
+ if (RT_FAILURE(rc2))
+ ModuleTerm = 0;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the symbol and string tables.
+ */
+ SUPLDRCREATETABSARGS CreateArgs;
+ CreateArgs.cbImage = CalcArgs.cbImage;
+ CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab];
+ CreateArgs.pszBase = (char *)&pLoadReq->u.In.achImage[offStrTab];
+ CreateArgs.psz = CreateArgs.pszBase;
+ rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
+ if (RT_SUCCESS(rc))
+ {
+ AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
+ AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab]) <= CalcArgs.cSymbols);
+
+ /*
+ * Upload the image.
+ */
+ pLoadReq->Hdr.u32Cookie = g_u32Cookie;
+ pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
+ pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImage);
+ pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
+ pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
+ pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
+
+ pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
+ pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
+ if (fIsVMMR0)
+ {
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)VMMR0EntryInt;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
+ pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
+ }
+ else if (pszSrvReqHandler)
+ {
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
+ pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
+ pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
+ pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
+ pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
+ }
+ else
+ pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
+ pLoadReq->u.In.offStrTab = offStrTab;
+ pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
+ AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
+ pLoadReq->u.In.offSymbols = offSymTab;
+ pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
+ pLoadReq->u.In.cbImage = cbImage;
+ pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
+ if (!g_u32FakeMode)
+ {
+ rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
+ if (RT_SUCCESS(rc))
+ rc = pLoadReq->Hdr.rc;
+ }
+ else
+ rc = VINF_SUCCESS;
+ if ( RT_SUCCESS(rc)
+ || rc == VERR_ALREADY_LOADED /* A competing process. */
+ )
+ {
+ LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr\n", pszModule, pszFilename,
+ OpenReq.u.Out.pvImageBase, ModuleInit, ModuleTerm));
+ if (fIsVMMR0)
+ {
+ g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
+ LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
+ VMMR0EntryEx, VMMR0EntryFast, VMMR0EntryInt));
+ }
+#ifdef RT_OS_WINDOWS
+ LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
+#endif
+
+ RTMemTmpFree(pLoadReq);
+ RTLdrClose(hLdrMod);
+ return VINF_SUCCESS;
+ }
+ }
+ }
+ }
+ RTMemTmpFree(pLoadReq);
+ }
+ else
+ {
+ AssertMsgFailed(("failed to allocated %d bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImage)));
+ rc = VERR_NO_TMP_MEMORY;
+ }
+ }
+ else if (RT_SUCCESS(rc))
+ {
+ if (fIsVMMR0)
+ g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
+ LogRel(("SUP: Opened %s (%s) at %#p.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase));
+#ifdef RT_OS_WINDOWS
+ LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
+#endif
+ }
+ }
+ RTLdrClose(hLdrMod);
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPFreeModule(void *pvImageBase)
+{
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ g_pvVMMR0 = NIL_RTR0PTR;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Free the requested module.
+ */
+ SUPLDRFREE Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if ( RT_SUCCESS(rc)
+ && (RTR0PTR)pvImageBase == g_pvVMMR0)
+ g_pvVMMR0 = NIL_RTR0PTR;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPGetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
+{
+ *ppvValue = NULL;
+
+ /* fake */
+ if (RT_UNLIKELY(g_u32FakeMode))
+ {
+ *ppvValue = (void *)(uintptr_t)0xdeadf00d;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Do ioctl.
+ */
+ SUPLDRGETSYMBOL Req;
+ Req.Hdr.u32Cookie = g_u32Cookie;
+ Req.Hdr.u32SessionCookie = g_u32SessionCookie;
+ Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
+ Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
+ Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
+ Req.Hdr.rc = VERR_INTERNAL_ERROR;
+ Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
+ size_t cchSymbol = strlen(pszSymbol);
+ if (cchSymbol >= sizeof(Req.u.In.szSymbol))
+ return VERR_SYMBOL_NOT_FOUND;
+ memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
+ int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
+ if (RT_SUCCESS(rc))
+ rc = Req.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ *ppvValue = (void *)Req.u.Out.pvSymbol;
+ return rc;
+}
+
+
+SUPR3DECL(int) SUPLoadVMM(const char *pszFilename)
+{
+ void *pvImageBase;
+ return SUPLoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
+}
+
+
+SUPR3DECL(int) SUPUnloadVMM(void)
+{
+ return SUPFreeModule((void*)g_pvVMMR0);
+}
+
+
+SUPR3DECL(int) SUPGipGetPhys(PRTHCPHYS pHCPhys)
+{
+ if (g_pSUPGlobalInfoPage)
+ {
+ *pHCPhys = g_HCPhysSUPGlobalInfoPage;
+ return VINF_SUCCESS;
+ }
+ *pHCPhys = NIL_RTHCPHYS;
+ return VERR_WRONG_ORDER;
+}
+
+
+/**
+ * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
+ *
+ * @returns iprt status code.
+ * @param pszFilename The full file name.
+ * @param phLdrMod Where to store the handle to the loaded module.
+ */
+static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod)
+{
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Verify the image file.
+ */
+ int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
+ return rc;
+ }
+#endif
+
+ /*
+ * Try load it.
+ */
+ return RTLdrLoad(pszFilename, phLdrMod);
+}
+
+
+SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod)
+{
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
+ *phLdrMod = NIL_RTLDRMOD;
+ AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
+
+ /*
+ * Add the default extension if it's missing.
+ */
+ if (!RTPathHaveExt(pszFilename))
+ {
+ const char *pszSuff = RTLdrGetSuff();
+ size_t cchSuff = strlen(pszSuff);
+ size_t cchFilename = strlen(pszFilename);
+ char *psz = (char *)alloca(cchFilename + cchSuff + 1);
+ AssertReturn(psz, VERR_NO_TMP_MEMORY);
+ memcpy(psz, pszFilename, cchFilename);
+ memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
+ pszFilename = psz;
+ }
+
+ /*
+ * Pass it on to the common library loader.
+ */
+ return supR3HardenedLdrLoadIt(pszFilename, phLdrMod);
+}
+
+
+SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod)
+{
+ LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p\n", pszFilename, pszFilename, phLdrMod));
+
+ /*
+ * Validate input.
+ */
+ AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
+ *phLdrMod = NIL_RTLDRMOD;
+ AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
+ AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check the filename.
+ */
+ size_t cchFilename = strlen(pszFilename);
+ AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
+
+ const char *pszExt = "";
+ size_t cchExt = 0;
+ if (!RTPathHaveExt(pszFilename))
+ {
+ pszExt = RTLdrGetSuff();
+ cchExt = strlen(pszExt);
+ }
+
+ /*
+ * Construct the private arch path and check if the file exists.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
+ AssertRCReturn(rc, rc);
+
+ char *psz = strchr(szPath, '\0');
+ *psz++ = RTPATH_SLASH;
+ memcpy(psz, pszFilename, cchFilename);
+ psz += cchFilename;
+ memcpy(psz, pszExt, cchExt + 1);
+
+ if (!RTPathExists(szPath))
+ {
+ LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
+ return VERR_FILE_NOT_FOUND;
+ }
+
+ /*
+ * Pass it on to SUPR3HardenedLdrLoad.
+ */
+ rc = SUPR3HardenedLdrLoad(szPath, phLdrMod);
+
+ LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPLibInternal.h b/src/VBox/HostDrivers/Support/SUPLibInternal.h
new file mode 100644
index 000000000..6b026256c
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPLibInternal.h
@@ -0,0 +1,324 @@
+/* $Id: SUPLibInternal.h 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Internal header.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPLibInternal_h___
+#define ___SUPLibInternal_h___
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <iprt/stdarg.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** @def SUPLIB_DLL_SUFF
+ * The (typical) DLL/DYLIB/SO suffix. */
+#if defined(RT_OS_DARWIN)
+# define SUPLIB_DLL_SUFF ".dylib"
+#elif defined(RT_OS_L4)
+# define SUPLIB_DLL_SUFF ".s.so"
+#elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+# define SUPLIB_DLL_SUFF ".dll"
+#else
+# define SUPLIB_DLL_SUFF ".so"
+#endif
+
+/** @def SUPLIB_EXE_SUFF
+ * The (typical) executable suffix. */
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+# define SUPLIB_EXE_SUFF ".exe"
+#else
+# define SUPLIB_EXE_SUFF ""
+#endif
+
+/** @def SUP_HARDENED_SUID
+ * Whether we're employing set-user-ID-on-execute in the hardening.
+ */
+#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
+# define SUP_HARDENED_SUID
+#else
+# undef SUP_HARDENED_SUID
+#endif
+
+#ifdef IN_SUP_HARDENED_R3
+/** @name Make the symbols in SUPR3HardenedStatic different from the VBoxRT ones.
+ * We cannot rely on DECLHIDDEN to make this separation for us since it doesn't
+ * work with all GCC versions. So, we resort to old fashion precompiler hacking.
+ * @{
+ */
+# define supR3HardenedPathAppPrivateNoArch supR3HardenedStaticPathAppPrivateNoArch
+# define supR3HardenedPathAppPrivateArch supR3HardenedStaticPathAppPrivateArch
+# define supR3HardenedPathSharedLibs supR3HardenedStaticPathSharedLibs
+# define supR3HardenedPathAppDocs supR3HardenedStaticPathAppDocs
+# define supR3HardenedPathProgram supR3HardenedStaticPathProgram
+# define supR3HardenedPathFilename supR3HardenedStaticPathFilename
+# define supR3HardenedFatalV supR3HardenedStaticFatalV
+# define supR3HardenedFatal supR3HardenedStaticFatal
+# define supR3HardenedFatalMsgV supR3HardenedStaticFatalMsgV
+# define supR3HardenedFatalMsg supR3HardenedStaticFatalMsg
+# define supR3HardenedErrorV supR3HardenedStaticErrorV
+# define supR3HardenedError supR3HardenedStaticError
+# define supR3HardenedVerifyAll supR3HardenedStaticVerifyAll
+# define supR3HardenedVerifyDir supR3HardenedStaticVerifyDir
+# define supR3HardenedVerifyFile supR3HardenedStaticVerifyFile
+# define supR3HardenedGetPreInitData supR3HardenedStaticGetPreInitData
+# define supR3HardenedRecvPreInitData supR3HardenedStaticRecvPreInitData
+/** @} */
+#endif /* IN_SUP_HARDENED_R3 */
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The negotiated interrupt number. */
+extern DECLHIDDEN(uint8_t) g_uchInterruptNo;
+/** The negotiated cookie. */
+extern DECLHIDDEN(uint32_t) g_u32Cookie;
+/** The negotiated cookie. */
+extern DECLHIDDEN(uint32_t) g_u32CookieSession;
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The type of an installed file.
+ */
+typedef enum SUPINSTFILETYPE
+{
+ kSupIFT_Invalid = 0,
+ kSupIFT_Exe,
+ kSupIFT_Dll,
+ kSupIFT_Sys,
+ kSupIFT_Script,
+ kSupIFT_Data,
+ kSupIFT_End
+} SUPINSTFILETYPE;
+
+/**
+ * Installation directory specifier.
+ */
+typedef enum SUPINSTDIR
+{
+ kSupID_Invalid = 0,
+ kSupID_Bin,
+ kSupID_AppBin,
+ kSupID_SharedLib,
+ kSupID_AppPrivArch,
+ kSupID_AppPrivArchComp,
+ kSupID_AppPrivNoArch,
+ kSupID_End
+} SUPINSTDIR;
+
+/**
+ * Installed file.
+ */
+typedef struct SUPINSTFILE
+{
+ /** File type. */
+ SUPINSTFILETYPE enmType;
+ /** Install directory. */
+ SUPINSTDIR enmDir;
+ /** Optional (true) or mandatory (false. */
+ bool fOptional;
+ /** File name. */
+ const char *pszFile;
+} SUPINSTFILE;
+typedef SUPINSTFILE *PSUPINSTFILE;
+typedef SUPINSTFILE const *PCSUPINSTFILE;
+
+/**
+ * Status data for a verified file.
+ */
+typedef struct SUPVERIFIEDFILE
+{
+ /** The file handle or descriptor. -1 if not open. */
+ intptr_t hFile;
+ /** Whether the file has been validated. */
+ bool fValidated;
+} SUPVERIFIEDFILE;
+typedef SUPVERIFIEDFILE *PSUPVERIFIEDFILE;
+typedef SUPVERIFIEDFILE const *PCSUPVERIFIEDFILE;
+
+/**
+ * Status data for a verified directory.
+ */
+typedef struct SUPVERIFIEDDIR
+{
+ /** The directory handle or descriptor. -1 if not open. */
+ intptr_t hDir;
+ /** Whether the directory has been validated. */
+ bool fValidated;
+} SUPVERIFIEDDIR;
+typedef SUPVERIFIEDDIR *PSUPVERIFIEDDIR;
+typedef SUPVERIFIEDDIR const *PCSUPVERIFIEDDIR;
+
+
+/**
+ * SUPLib instance data.
+ *
+ * This is data that is passed from the static to the dynamic SUPLib
+ * in a hardened setup.
+ */
+typedef struct SUPLIBDATA
+{
+ /** The device handle. */
+ RTFILE hDevice;
+#if defined(RT_OS_DARWIN)
+ /** The connection to the VBoxSupDrv service. */
+ void *pvConnection;
+#elif defined(RT_OS_LINUX)
+ /** Indicates whether madvise(,,MADV_DONTFORK) works. */
+ bool fSysMadviseWorks;
+#elif defined(RT_OS_WINDOWS)
+#endif
+} SUPLIBDATA;
+/** Pointer to the pre-init data. */
+typedef SUPLIBDATA *PSUPLIBDATA;
+/** Pointer to const pre-init data. */
+typedef SUPLIBDATA const *PCSUPLIBDATA;
+
+
+/**
+ * Pre-init data that is handed over from the hardened executable stub.
+ */
+typedef struct SUPPREINITDATA
+{
+ /** Magic value (SUPPREINITDATA_MAGIC). */
+ uint32_t u32Magic;
+ /** The SUPLib instance data. */
+ SUPLIBDATA Data;
+ /** The number of entries in paInstallFiles and paVerifiedFiles. */
+ size_t cInstallFiles;
+ /** g_aSupInstallFiles. */
+ PCSUPINSTFILE paInstallFiles;
+ /** g_aSupVerifiedFiles. */
+ PCSUPVERIFIEDFILE paVerifiedFiles;
+ /** The number of entries in paVerifiedDirs. */
+ size_t cVerifiedDirs;
+ /** g_aSupVerifiedDirs. */
+ PCSUPVERIFIEDDIR paVerifiedDirs;
+ /** Magic value (SUPPREINITDATA_MAGIC). */
+ uint32_t u32EndMagic;
+} SUPPREINITDATA;
+typedef SUPPREINITDATA *PSUPPREINITDATA;
+typedef SUPPREINITDATA const *PCSUPPREINITDATA;
+
+/** Magic value for SUPPREINITDATA::u32Magic and SUPPREINITDATA::u32EndMagic. */
+#define SUPPREINITDATA_MAGIC UINT32_C(0xbeef0001)
+
+/** @copydoc supR3PreInit */
+typedef DECLCALLBACK(int) FNSUPR3PREINIT(PSUPPREINITDATA pPreInitData, uint32_t fFlags);
+/** Pointer to supR3PreInit. */
+typedef FNSUPR3PREINIT *PFNSUPR3PREINIT;
+
+
+/*******************************************************************************
+* OS Specific Function *
+*******************************************************************************/
+__BEGIN_DECLS
+int suplibOsInstall(void);
+int suplibOsUninstall(void);
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited);
+int suplibOsTerm(PSUPLIBDATA pThis);
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq);
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu);
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages);
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages);
+
+
+/**
+ * Performs the pre-initialization of the support library.
+ *
+ * This is dynamically resolved and invoked by the static library before it
+ * calls RTR3Init and thereby SUPR3Init.
+ *
+ * @returns IPRT status code.
+ * @param pPreInitData The pre init data.
+ * @param fFlags The SUPR3HardenedMain flags.
+ */
+DECLEXPORT(int) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags);
+
+
+/** @copydoc RTPathAppPrivateNoArch */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath);
+/** @copydoc RTPathAppPrivateArch */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath);
+/** @copydoc RTPathSharedLibs */
+DECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath);
+/** @copydoc RTPathAppDocs */
+DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath);
+/** @copydoc RTPathProgram */
+DECLHIDDEN(int) supR3HardenedPathProgram(char *pszPath, size_t cchPath);
+/** @copydoc RTPathFilename */
+DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath);
+
+/**
+ * Display a fatal error and try call TrustedError or quit.
+ */
+DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va);
+
+/**
+ * Display a fatal error and try call TrustedError or quit.
+ */
+DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...);
+
+/**
+ * Display a fatal error and quit.
+ */
+DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va);
+
+/**
+ * Display a fatal error and quit.
+ */
+DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...);
+
+/**
+ * Display an error which may or may not be fatal.
+ */
+DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va);
+
+/**
+ * Display an error which may or may not be fatal.
+ */
+DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...);
+DECLHIDDEN(int) supR3HardenedVerifyAll(bool fFatal, bool fLeaveFilesOpen, const char *pszProgName);
+DECLHIDDEN(int) supR3HardenedVerifyDir(SUPINSTDIR enmDir, bool fFatal);
+DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, bool fFatal);
+DECLHIDDEN(void) supR3HardenedGetPreInitData(PSUPPREINITDATA pPreInitData);
+DECLHIDDEN(int) supR3HardenedRecvPreInitData(PCSUPPREINITDATA pPreInitData);
+
+
+__END_DECLS
+
+
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/SUPR0.def b/src/VBox/HostDrivers/Support/SUPR0.def
new file mode 100644
index 000000000..659532b0d
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR0.def
@@ -0,0 +1,129 @@
+; $Id: SUPR0.def 15838 2009-01-07 15:57:24Z vboxsync $
+;; @file
+; VirtualBox Support Driver - Built-in exports.
+;
+
+;
+; Copyright (C) 2006-2007 Sun Microsystems, Inc.
+;
+; 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.
+;
+; Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+; Clara, CA 95054 USA or visit http://www.sun.com if you need
+; additional information or have any questions.
+;
+
+LIBRARY SUPR0.dll
+
+EXPORTS
+ SUPR0AbsIs64bit
+ SUPR0Abs64bitKernelCS
+ SUPR0Abs64bitKernelSS
+ SUPR0Abs64bitKernelDS
+ SUPR0ComponentRegisterFactory
+ SUPR0ComponentDeregisterFactory
+ SUPR0ComponentQueryFactory
+ SUPR0ObjRegister
+ SUPR0ObjAddRef
+ SUPR0ObjAddRefEx
+ SUPR0ObjRelease
+ SUPR0ObjVerifyAccess
+ SUPR0LockMem
+ SUPR0UnlockMem
+ SUPR0ContAlloc
+ SUPR0ContFree
+ SUPR0LowAlloc
+ SUPR0LowFree
+ SUPR0MemAlloc
+ SUPR0MemGetPhys
+ SUPR0MemFree
+ SUPR0Printf
+ SUPR0GetPagingMode
+ SUPR0EnableVTx
+ RTMemAlloc
+ RTMemAllocZ
+ RTMemFree
+ RTMemRealloc
+ RTR0MemObjAllocLow
+ RTR0MemObjAllocPage
+ RTR0MemObjAllocPhys
+ RTR0MemObjAllocPhysNC
+ RTR0MemObjAllocCont
+ RTR0MemObjLockUser
+ RTR0MemObjMapKernel
+ RTR0MemObjMapUser
+ RTR0MemObjAddress
+ RTR0MemObjAddressR3
+ RTR0MemObjSize
+ RTR0MemObjIsMapping
+ RTR0MemObjGetPagePhysAddr
+ RTR0MemObjFree
+ ; broken - RTSemMutexCreate
+ ; broken - RTSemMutexRequest
+ ; broken - RTSemMutexRelease
+ ; broken - RTSemMutexDestroy
+ RTSemEventCreate
+ RTSemEventSignal
+ RTSemEventWait
+ RTSemEventWaitNoResume
+ RTSemEventDestroy
+ RTSemEventMultiCreate
+ RTSemEventMultiSignal
+ RTSemEventMultiReset
+ RTSemEventMultiWait
+ RTSemEventMultiWaitNoResume
+ RTSemEventMultiDestroy
+ RTSemFastMutexCreate
+ RTSemFastMutexDestroy
+ RTSemFastMutexRequest
+ RTSemFastMutexRelease
+ RTSpinlockCreate
+ RTSpinlockDestroy
+ RTSpinlockAcquire
+ RTSpinlockRelease
+ RTSpinlockAcquireNoInts
+ RTSpinlockReleaseNoInts
+ RTTimeNanoTS
+ RTTimeMillieTS
+ RTTimeSystemNanoTS
+ RTTimeSystemMillieTS
+ RTThreadSelf
+ RTThreadNativeSelf
+ RTThreadSleep
+ RTThreadYield
+ RTMpOnAll
+ RTMpOnOthers
+ RTMpOnSpecific
+ RTMpIsCpuOnline
+ RTMpGetCount
+ RTMpCpuIdToSetIndex
+ RTMpCpuId
+ RTMpIsCpuWorkPending
+ RTPowerNotificationRegister
+ RTPowerNotificationDeregister
+ RTLogDefaultInstance
+ RTLogRelDefaultInstance
+ RTLogSetDefaultInstanceThread
+ RTLogLoggerExV
+ RTLogPrintfV
+ AssertMsg1
+ AssertMsg2
+
+ ; data
+ g_SUPGlobalInfoPage DATA
+
diff --git a/src/VBox/HostDrivers/Support/SUPR0IdcClient.c b/src/VBox/HostDrivers/Support/SUPR0IdcClient.c
new file mode 100644
index 000000000..fed29823d
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR0IdcClient.c
@@ -0,0 +1,214 @@
+/* $Id: SUPR0IdcClient.c 11794 2008-08-29 09:13:37Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Core.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+static PSUPDRVIDCHANDLE volatile g_pMainHandle = NULL;
+
+
+/**
+ * Opens the IDC interface of the support driver.
+ *
+ * This will perform basic version negotiations and fail if the
+ * minmum requirements aren't met.
+ *
+ * @returns VBox status code.
+ * @param pHandle The handle structure (output).
+ * @param uReqVersion The requested version. Pass 0 for default.
+ * @param uMinVersion The minimum required version. Pass 0 for default.
+ * @param puSessionVersion Where to store the session version. Optional.
+ * @param puDriverVersion Where to store the session version. Optional.
+ * @param puDriverRevision Where to store the SVN revision of the driver. Optional.
+ */
+SUPR0DECL(int) SUPR0IdcOpen(PSUPDRVIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion,
+ uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision)
+{
+ unsigned uDefaultMinVersion;
+ SUPDRVIDCREQCONNECT Req;
+ int rc;
+
+ /*
+ * Validate and set failure return values.
+ */
+ AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
+ pHandle->s.pSession = NULL;
+
+ AssertPtrNullReturn(puSessionVersion, VERR_INVALID_POINTER);
+ if (puSessionVersion)
+ *puSessionVersion = 0;
+
+ AssertPtrNullReturn(puDriverVersion, VERR_INVALID_POINTER);
+ if (puDriverVersion)
+ *puDriverVersion = 0;
+
+ AssertPtrNullReturn(puDriverRevision, VERR_INVALID_POINTER);
+ if (puDriverRevision)
+ *puDriverRevision = 0;
+
+ AssertReturn(!uMinVersion || (uMinVersion & UINT32_C(0xffff0000)) == (SUPDRV_IDC_VERSION & UINT32_C(0xffff0000)), VERR_INVALID_PARAMETER);
+ AssertReturn(!uReqVersion || (uReqVersion & UINT32_C(0xffff0000)) == (SUPDRV_IDC_VERSION & UINT32_C(0xffff0000)), VERR_INVALID_PARAMETER);
+
+ /*
+ * Handle default version input and enforce minimum requirements made
+ * by this library.
+ *
+ * The clients will pass defaults (0), and only in the case that some
+ * special API feature was just added will they set an actual version.
+ * So, this is the place where can easily enforce a minimum IDC version
+ * on bugs and similar. It corresponds a bit to what SUPR3Init is
+ * responsible for.
+ */
+ uDefaultMinVersion = SUPDRV_IDC_VERSION & UINT32_C(0xffff0000);
+ if (!uMinVersion || uMinVersion < uDefaultMinVersion)
+ uMinVersion = uDefaultMinVersion;
+ if (!uReqVersion || uReqVersion < uDefaultMinVersion)
+ uReqVersion = uDefaultMinVersion;
+
+ /*
+ * Setup the connect request packet and call the OS specific function.
+ */
+ Req.Hdr.cb = sizeof(Req);
+ Req.Hdr.rc = VERR_WRONG_ORDER;
+ Req.Hdr.pSession = NULL;
+ Req.u.In.u32MagicCookie = SUPDRVIDCREQ_CONNECT_MAGIC_COOKIE;
+ Req.u.In.uMinVersion = uMinVersion;
+ Req.u.In.uReqVersion = uReqVersion;
+ rc = supR0IdcNativeOpen(pHandle, &Req);
+ if (RT_SUCCESS(rc))
+ {
+ pHandle->s.pSession = Req.u.Out.pSession;
+ if (puSessionVersion)
+ *puSessionVersion = Req.u.Out.uSessionVersion;
+ if (puDriverVersion)
+ *puDriverVersion = Req.u.Out.uDriverVersion;
+ if (puDriverRevision)
+ *puDriverRevision = Req.u.Out.uDriverRevision;
+
+ /*
+ * We don't really trust anyone, make sure the returned
+ * session and version values actually makes sense.
+ */
+ if ( VALID_PTR(Req.u.Out.pSession)
+ && Req.u.Out.uSessionVersion >= uMinVersion
+ && (Req.u.Out.uSessionVersion & UINT32_C(0xffff0000)) == (SUPDRV_IDC_VERSION & UINT32_C(0xffff0000)))
+ {
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pMainHandle, pHandle, NULL);
+ return rc;
+ }
+
+ AssertMsgFailed(("pSession=%p uSessionVersion=0x%x (r%u)\n", Req.u.Out.pSession, Req.u.Out.uSessionVersion, Req.u.Out.uDriverRevision));
+ rc = VERR_VERSION_MISMATCH;
+ SUPR0IdcClose(pHandle);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Closes a IDC connection established by SUPR0IdcOpen.
+ *
+ * @returns VBox status code.
+ * @param pHandle The IDC handle.
+ */
+SUPR0DECL(int) SUPR0IdcClose(PSUPDRVIDCHANDLE pHandle)
+{
+ SUPDRVIDCREQHDR Req;
+ int rc;
+
+ /*
+ * Catch closed handles and check that the session is valid.
+ */
+ AssertPtrReturn(pHandle, VERR_INVALID_POINTER);
+ if (!pHandle->s.pSession)
+ return VERR_INVALID_HANDLE;
+ AssertPtrReturn(pHandle->s.pSession, VERR_INVALID_HANDLE);
+
+ /*
+ * Create the request and hand it to the OS specific code.
+ */
+ Req.cb = sizeof(Req);
+ Req.rc = VERR_WRONG_ORDER;
+ Req.pSession = pHandle->s.pSession;
+ rc = supR0IdcNativeClose(pHandle, &Req);
+ if (RT_SUCCESS(rc))
+ {
+ pHandle->s.pSession = NULL;
+ ASMAtomicCmpXchgPtr((void * volatile *)&g_pMainHandle, NULL, pHandle);
+ }
+ return rc;
+}
+
+
+/**
+ * Get the SUPDRV session for the IDC connection.
+ *
+ * This is for use with SUPDRV and component APIs that requires a valid
+ * session handle.
+ *
+ * @returns The session handle on success, NULL if the IDC handle is invalid.
+ *
+ * @param pHandle The IDC handle.
+ */
+SUPR0DECL(PSUPDRVSESSION) SUPR0IdcGetSession(PSUPDRVIDCHANDLE pHandle)
+{
+ PSUPDRVSESSION pSession;
+ AssertPtrReturn(pHandle, NULL);
+ pSession = pHandle->s.pSession;
+ AssertPtrReturn(pSession, NULL);
+ return pSession;
+}
+
+
+/**
+ * Looks up a IDC handle by session.
+ *
+ * @returns The IDC handle on success, NULL on failure.
+ * @param pSession The session to lookup.
+ *
+ * @internal
+ */
+PSUPDRVIDCHANDLE supR0IdcGetHandleFromSession(PSUPDRVSESSION pSession)
+{
+ PSUPDRVIDCHANDLE pHandle = (PSUPDRVIDCHANDLE)ASMAtomicUoReadPtr((void * volatile *)&g_pMainHandle);
+ if ( VALID_PTR(pHandle)
+ && pHandle->s.pSession == pSession)
+ return pHandle;
+ return NULL;
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c b/src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c
new file mode 100644
index 000000000..523b0c5e5
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c
@@ -0,0 +1,94 @@
+/* $Id: SUPR0IdcClientComponent.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Component APIs.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+/**
+ * Registers a component factory with SUPDRV.
+ *
+ * @returns VBox status code.
+ * @param pHandle The IDC handle.
+ * @param pFactory The factory to register.
+ */
+SUPR0DECL(int) SUPR0IdcComponentRegisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory)
+{
+ SUPDRVIDCREQCOMPREGFACTORY Req;
+
+ /*
+ * Validate the handle before we access it.
+ */
+ AssertPtrReturn(pHandle, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pHandle->s.pSession, VERR_INVALID_HANDLE);
+
+ /*
+ * Construct and fire off the request.
+ */
+ Req.Hdr.cb = sizeof(Req);
+ Req.Hdr.rc = VERR_WRONG_ORDER;
+ Req.Hdr.pSession = pHandle->s.pSession;
+ Req.u.In.pFactory = pFactory;
+
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_COMPONENT_REGISTER_FACTORY, &Req.Hdr);
+}
+
+
+/**
+ * Deregisters a component factory with SUPDRV.
+ *
+ * @returns VBox status code.
+ * @param pHandle The IDC handle.
+ * @param pFactory The factory to register.
+ */
+SUPR0DECL(int) SUPR0IdcComponentDeregisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory)
+{
+ SUPDRVIDCREQCOMPDEREGFACTORY Req;
+
+ /*
+ * Validate the handle before we access it.
+ */
+ AssertPtrReturn(pHandle, VERR_INVALID_HANDLE);
+ AssertPtrReturn(pHandle->s.pSession, VERR_INVALID_HANDLE);
+
+ /*
+ * Construct and fire off the request.
+ */
+ Req.Hdr.cb = sizeof(Req);
+ Req.Hdr.rc = VERR_WRONG_ORDER;
+ Req.Hdr.pSession = pHandle->s.pSession;
+ Req.u.In.pFactory = pFactory;
+
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_COMPONENT_DEREGISTER_FACTORY, &Req.Hdr);
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h b/src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h
new file mode 100644
index 000000000..22133089b
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h
@@ -0,0 +1,88 @@
+/* $Id: SUPR0IdcClientInternal.h 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - Internal header for the IDC client library.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPR0IdcClientInternal_h__
+#define ___SUPR0IdcClientInternal_h__
+
+#include <VBox/types.h>
+#include <iprt/assert.h>
+
+#ifdef RT_OS_WINDOWS
+# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
+# include <iprt/asm.h>
+# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
+# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
+# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
+# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
+__BEGIN_DECLS
+# include <ntddk.h>
+__END_DECLS
+# undef _InterlockedExchange
+# undef _InterlockedExchangeAdd
+# undef _InterlockedCompareExchange
+# undef _InterlockedAddLargeStatistic
+# else
+__BEGIN_DECLS
+# include <ntddk.h>
+__END_DECLS
+# endif
+#endif /* RT_OS_WINDOWS */
+
+
+/**
+ * The hidden part of SUPDRVIDCHANDLE.
+ */
+struct SUPDRVIDCHANDLEPRIVATE
+{
+ /** Pointer to the session handle. */
+ PSUPDRVSESSION pSession;
+# ifdef RT_OS_WINDOWS
+ /** Pointer to the NT device object. */
+ PDEVICE_OBJECT pDeviceObject;
+ /** Pointer to the NT file object. */
+ PFILE_OBJECT pFileObject;
+# endif
+};
+/** Indicate that the structure is present. */
+#define SUPDRVIDCHANDLEPRIVATE_DECLARED 1
+
+#include <VBox/sup.h>
+#include "SUPDrvIDC.h"
+AssertCompile(RT_SIZEOFMEMB(SUPDRVIDCHANDLE, apvPadding) >= sizeof(struct SUPDRVIDCHANDLEPRIVATE));
+
+__BEGIN_DECLS
+PSUPDRVIDCHANDLE supR0IdcGetHandleFromSession(PSUPDRVSESSION pSession);
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq);
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq);
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq);
+__END_DECLS
+
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/SUPR0IdcClientStubs.c b/src/VBox/HostDrivers/Support/SUPR0IdcClientStubs.c
new file mode 100644
index 000000000..7a21a84c9
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR0IdcClientStubs.c
@@ -0,0 +1,147 @@
+/* $Id: SUPR0IdcClientStubs.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Stubs for SUPR0 APIs.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+/**
+ * Resolves a symbol.
+ *
+ * @returns Pointer to the symbol on success, NULL on failure.
+ *
+ * @param pHandle The IDC handle.
+ * @param pszName The name of the symbol.
+ */
+static void supR0IdcGetSymbol(PSUPDRVIDCHANDLE pHandle, PFNRT *ppfn, const char *pszName)
+{
+ SUPDRVIDCREQGETSYM Req;
+ int rc;
+
+ /*
+ * Create and send a get symbol request.
+ */
+ Req.Hdr.cb = sizeof(Req);
+ Req.Hdr.rc = VERR_WRONG_ORDER;
+ Req.Hdr.pSession = pHandle->s.pSession;
+ Req.u.In.pszSymbol = pszName;
+ Req.u.In.pszModule = NULL;
+ rc = supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_GET_SYMBOL, &Req.Hdr);
+ if (RT_SUCCESS(rc))
+ ASMAtomicWritePtr((void * volatile *)ppfn, Req.u.Out.pfnSymbol);
+}
+
+
+/**
+ * Resolves a symbol.
+ *
+ * @returns Pointer to the symbol on success, NULL on failure.
+ *
+ * @param pHandle The IDC handle.
+ * @param pszName The name of the symbol.
+ */
+static void supR0IdcGetSymbolBySession(PSUPDRVSESSION pSession, PFNRT *ppfn, const char *pszName)
+{
+ PSUPDRVIDCHANDLE pHandle = supR0IdcGetHandleFromSession(pSession);
+ if (pHandle)
+ supR0IdcGetSymbol(pHandle, ppfn, pszName);
+}
+
+
+SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
+{
+ static DECLCALLBACKPTR(void *, s_pfn)(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2);
+ DECLCALLBACKPTR(void *, pfn)(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2);
+ pfn = s_pfn;
+ if (!pfn)
+ {
+ supR0IdcGetSymbolBySession(pSession, (PFNRT *)&s_pfn, "SUPR0ObjRegister");
+ pfn = s_pfn;
+ if (!pfn)
+ return NULL;
+ }
+
+ return pfn(pSession, enmType, pfnDestructor, pvUser1, pvUser2);
+}
+
+
+SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
+{
+ static DECLCALLBACKPTR(int, s_pfn)(void *pvObj, PSUPDRVSESSION pSession);
+ DECLCALLBACKPTR(int, pfn)(void *pvObj, PSUPDRVSESSION pSession);
+ pfn = s_pfn;
+ if (!pfn)
+ {
+ supR0IdcGetSymbolBySession(pSession, (PFNRT *)&s_pfn, "SUPR0ObjAddRef");
+ pfn = s_pfn;
+ if (!pfn)
+ return VERR_NOT_SUPPORTED;
+ }
+
+ return pfn(pvObj, pSession);
+}
+
+
+SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
+{
+ static DECLCALLBACKPTR(int, s_pfn)(void *pvObj, PSUPDRVSESSION pSession);
+ DECLCALLBACKPTR(int, pfn)(void *pvObj, PSUPDRVSESSION pSession);
+ pfn = s_pfn;
+ if (!pfn)
+ {
+ supR0IdcGetSymbolBySession(pSession, (PFNRT *)&s_pfn, "SUPR0ObjRelease");
+ pfn = s_pfn;
+ if (!pfn)
+ return VERR_NOT_SUPPORTED;
+ }
+
+ return pfn(pvObj, pSession);
+}
+
+
+SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
+{
+ static DECLCALLBACKPTR(int, s_pfn)(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
+ DECLCALLBACKPTR(int, pfn)(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
+ pfn = s_pfn;
+ if (!pfn)
+ {
+ supR0IdcGetSymbolBySession(pSession, (PFNRT *)&s_pfn, "SUPR0ObjVerifyAccess");
+ pfn = s_pfn;
+ if (!pfn)
+ return VERR_NOT_SUPPORTED;
+ }
+
+ return pfn(pvObj, pSession, pszObjName);
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedIPRT.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedIPRT.cpp
new file mode 100644
index 000000000..08fea59f5
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedIPRT.cpp
@@ -0,0 +1,160 @@
+/* $Id: SUPR3HardenedIPRT.cpp 15352 2008-12-12 06:08:19Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Hardened Support Routines using IPRT.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#include <iprt/assert.h>
+#include <iprt/path.h>
+#include <iprt/param.h>
+
+#include "SUPLibInternal.h"
+
+
+/**
+ * @copydoc RTPathFilename
+ */
+DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
+{
+ return RTPathFilename(pszPath);
+}
+
+
+/**
+ * @copydoc RTPathAppPrivateNoArch
+ */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
+{
+ return RTPathAppPrivateNoArch(pszPath, cchPath);
+}
+
+
+/**
+ * @copydoc RTPathAppPrivateArch
+ */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
+{
+ return RTPathAppPrivateArch(pszPath, cchPath);
+}
+
+
+/**
+ * @copydoc RTPathSharedLibs
+ */
+DECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath)
+{
+ return RTPathSharedLibs(pszPath, cchPath);
+}
+
+
+/**
+ * @copydoc RTPathAppDocs
+ */
+DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
+{
+ return RTPathAppDocs(pszPath, cchPath);
+}
+
+
+/**
+ * @copydoc RTPathProgram
+ */
+DECLHIDDEN(int) supR3HardenedPathProgram(char *pszPath, size_t cchPath)
+{
+ return RTPathProgram(pszPath, cchPath);
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
+{
+ va_list vaCopy;
+ va_copy(vaCopy, va);
+ AssertFatalMsgFailed(("%s (rc=%Rrc): %N", pszWhere, rc, pszMsgFmt, &vaCopy));
+ va_end(vaCopy);
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
+{
+ va_list va;
+ va_start(va, pszMsgFmt);
+ supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
+ va_end(va);
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
+{
+ va_list vaCopy;
+ va_copy(vaCopy, va);
+ AssertFatalMsgFailed(("%N", pszFormat, &vaCopy));
+ va_end(vaCopy);
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supR3HardenedFatalV(pszFormat, va);
+ va_end(va);
+}
+
+
+DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
+{
+ if (fFatal)
+ supR3HardenedFatalV(pszFormat, va);
+
+ va_list vaCopy;
+ va_copy(vaCopy, va);
+ AssertLogRelMsgFailed(("%N", pszFormat, &vaCopy)); /** @todo figure out why this ain't working, or at seems to be that way... */
+ va_end(vaCopy);
+
+ RTLogRelPrintfV(pszFormat, va);
+ return rc;
+}
+
+
+DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supR3HardenedErrorV(rc, fFatal, pszFormat, va);
+ va_end(va);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
new file mode 100644
index 000000000..58adb1a0f
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
@@ -0,0 +1,1068 @@
+/* $Id: SUPR3HardenedMain.cpp 16067 2009-01-20 07:52:25Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Hardened main().
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#if defined(RT_OS_OS2)
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <dlfcn.h>
+
+#elif RT_OS_WINDOWS
+# include <Windows.h>
+# include <stdio.h>
+
+#else /* UNIXes */
+# include <iprt/types.h> /* stdint fun on darwin. */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <dlfcn.h>
+# include <limits.h>
+# include <errno.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <stdio.h>
+# include <sys/types.h>
+# if defined(RT_OS_LINUX)
+# undef USE_LIB_PCAP /* don't depend on libcap as we had to depend on either
+ libcap1 or libcap2 */
+
+# undef _POSIX_SOURCE
+# include <sys/capability.h>
+# include <sys/prctl.h>
+# ifndef CAP_TO_MASK
+# define CAP_TO_MASK(cap) RT_BIT(cap)
+# endif
+# elif defined(RT_OS_SOLARIS)
+# include <priv.h>
+# endif
+# include <pwd.h>
+# ifdef RT_OS_DARWIN
+# include <mach-o/dyld.h>
+# endif
+
+#endif
+
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/string.h>
+#include <iprt/param.h>
+
+#include "SUPLibInternal.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** @def SUP_HARDENED_SUID
+ * Whether we're employing set-user-ID-on-execute in the hardening.
+ */
+#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
+# define SUP_HARDENED_SUID
+#else
+# undef SUP_HARDENED_SUID
+#endif
+
+/** @def SUP_HARDENED_SYM
+ * Decorate a symbol that's resolved dynamically.
+ */
+#ifdef RT_OS_OS2
+# define SUP_HARDENED_SYM(sym) "_" sym
+#else
+# define SUP_HARDENED_SYM(sym) sym
+#endif
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** @see RTR3InitEx */
+typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, const char *pszProgramPath, bool fInitSUPLib);
+typedef FNRTR3INITEX *PFNRTR3INITEX;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The pre-init data we pass on to SUPR3 (residing in VBoxRT). */
+static SUPPREINITDATA g_SupPreInitData;
+/** The progam executable path. */
+static char g_szSupLibHardenedExePath[RTPATH_MAX];
+/** The program directory path. */
+static char g_szSupLibHardenedDirPath[RTPATH_MAX];
+
+/** The program name. */
+static const char *g_pszSupLibHardenedProgName;
+
+#ifdef SUP_HARDENED_SUID
+/** The real UID at startup. */
+static uid_t g_uid;
+/** The real GID at startup. */
+static gid_t g_gid;
+# ifdef RT_OS_LINUX
+static uint32_t g_uCaps;
+# endif
+#endif
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+#ifdef SUP_HARDENED_SUID
+static void supR3HardenedMainDropPrivileges(void);
+#endif
+static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName);
+
+
+/**
+ * @copydoc RTPathStripFilename.
+ */
+static void suplibHardenedPathStripFilename(char *pszPath)
+{
+ char *psz = pszPath;
+ char *pszLastSep = pszPath;
+
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ case ':':
+ pszLastSep = psz + 1;
+ break;
+
+ case '\\':
+#endif
+ case '/':
+ pszLastSep = psz;
+ break;
+
+ /* the end */
+ case '\0':
+ if (pszLastSep == pszPath)
+ *pszLastSep++ = '.';
+ *pszLastSep = '\0';
+ return;
+ }
+ }
+ /* will never get here */
+}
+
+
+/**
+ * @copydoc RTPathFilename
+ */
+DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
+{
+ const char *psz = pszPath;
+ const char *pszLastComp = pszPath;
+
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ case ':':
+ pszLastComp = psz + 1;
+ break;
+
+ case '\\':
+#endif
+ case '/':
+ pszLastComp = psz + 1;
+ break;
+
+ /* the end */
+ case '\0':
+ if (*pszLastComp)
+ return (char *)(void *)pszLastComp;
+ return NULL;
+ }
+ }
+
+ /* will never get here */
+ return NULL;
+}
+
+
+/**
+ * @copydoc RTPathAppPrivateNoArch
+ */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
+{
+#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
+ const char *pszSrcPath = RTPATH_APP_PRIVATE;
+ size_t cchPathPrivateNoArch = strlen(pszSrcPath);
+ if (cchPathPrivateNoArch >= cchPath)
+ supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %lu >= %lu\n",
+ (unsigned long)cchPathPrivateNoArch, (unsigned long)cchPath);
+ memcpy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
+ return VINF_SUCCESS;
+
+#else
+ return supR3HardenedPathProgram(pszPath, cchPath);
+#endif
+}
+
+
+/**
+ * @copydoc RTPathAppPrivateArch
+ */
+DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
+{
+#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
+ const char *pszSrcPath = RTPATH_APP_PRIVATE_ARCH;
+ size_t cchPathPrivateArch = strlen(pszSrcPath);
+ if (cchPathPrivateArch >= cchPath)
+ supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %lu >= %lu\n",
+ (unsigned long)cchPathPrivateArch, (unsigned long)cchPath);
+ memcpy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
+ return VINF_SUCCESS;
+
+#else
+ return supR3HardenedPathProgram(pszPath, cchPath);
+#endif
+}
+
+
+/**
+ * @copydoc RTPathSharedLibs
+ */
+DECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath)
+{
+#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
+ const char *pszSrcPath = RTPATH_SHARED_LIBS;
+ size_t cchPathSharedLibs = strlen(pszSrcPath);
+ if (cchPathSharedLibs >= cchPath)
+ supR3HardenedFatal("supR3HardenedPathSharedLibs: Buffer overflow, %lu >= %lu\n",
+ (unsigned long)cchPathSharedLibs, (unsigned long)cchPath);
+ memcpy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
+ return VINF_SUCCESS;
+
+#else
+ return supR3HardenedPathProgram(pszPath, cchPath);
+#endif
+}
+
+
+/**
+ * @copydoc RTPathAppDocs
+ */
+DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
+{
+#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
+ const char *pszSrcPath = RTPATH_APP_DOCS;
+ size_t cchPathAppDocs = strlen(pszSrcPath);
+ if (cchPathAppDocs >= cchPath)
+ supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %lu >= %lu\n",
+ (unsigned long)cchPathAppDocs, (unsigned long)cchPath);
+ memcpy(pszPath, pszSrcPath, cchPathAppDocs + 1);
+ return VINF_SUCCESS;
+
+#else
+ return supR3HardenedPathProgram(pszPath, cchPath);
+#endif
+}
+
+
+/**
+ * Returns the full path to the executable.
+ *
+ * @returns IPRT status code.
+ * @param pszPath Where to store it.
+ * @param cchPath How big that buffer is.
+ */
+static void supR3HardenedGetFullExePath(void)
+{
+ /*
+ * Get the program filename.
+ *
+ * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
+ * link in the proc file system that tells who was exec'ed. The bad thing about this
+ * is that we have to use readlink, one of the weirder UNIX APIs.
+ *
+ * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
+ */
+#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
+# ifdef RT_OS_LINUX
+ int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
+# elif defined(RT_OS_SOLARIS)
+ char szFileBuf[PATH_MAX + 1];
+ sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
+ int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
+# else /* RT_OS_FREEBSD: */
+ int cchLink = readlink("/proc/curproc/file", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
+# endif
+ if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
+ supR3HardenedFatal("supR3HardenedPathProgram: couldn't read \"%s\", errno=%d cchLink=%d\n",
+ g_szSupLibHardenedExePath, errno, cchLink);
+ g_szSupLibHardenedExePath[cchLink] = '\0';
+
+#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
+ _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
+
+#elif defined(RT_OS_DARWIN)
+ const char *pszImageName = _dyld_get_image_name(0);
+ if (!pszImageName)
+ supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed\n");
+ size_t cchImageName = strlen(pszImageName);
+ if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
+ supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
+ memcpy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
+
+#elif defined(RT_OS_WINDOWS)
+ HMODULE hExe = GetModuleHandle(NULL);
+ if (!GetModuleFileName(hExe, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath)))
+ supR3HardenedFatal("supR3HardenedPathProgram: GetModuleFileName failed, rc=%d\n", GetLastError());
+#else
+# error needs porting.
+#endif
+
+ /*
+ * Strip off the filename part (RTPathStripFilename()).
+ */
+ strcpy(g_szSupLibHardenedDirPath, g_szSupLibHardenedExePath);
+ suplibHardenedPathStripFilename(g_szSupLibHardenedDirPath);
+}
+
+
+#ifdef RT_OS_LINUX
+/**
+ * Checks if we can read /proc/self/exe.
+ *
+ * This is used on linux to see if we have to call init
+ * with program path or not.
+ *
+ * @returns true / false.
+ */
+static bool supR3HardenedMainIsProcSelfExeAccssible(void)
+{
+ char szPath[RTPATH_MAX];
+ int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
+ return cchLink != -1;
+}
+#endif /* RT_OS_LINUX */
+
+
+
+/**
+ * @copydoc RTPathProgram
+ */
+DECLHIDDEN(int) supR3HardenedPathProgram(char *pszPath, size_t cchPath)
+{
+ /*
+ * Lazy init (probably not required).
+ */
+ if (!g_szSupLibHardenedDirPath[0])
+ supR3HardenedGetFullExePath();
+
+ /*
+ * Calc the length and check if there is space before copying.
+ */
+ unsigned cch = strlen(g_szSupLibHardenedDirPath) + 1;
+ if (cch <= cchPath)
+ {
+ memcpy(pszPath, g_szSupLibHardenedDirPath, cch + 1);
+ return VINF_SUCCESS;
+ }
+
+ supR3HardenedFatal("supR3HardenedPathProgram: Buffer too small (%u < %u)\n", cchPath, cch);
+ return VERR_BUFFER_OVERFLOW;
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
+{
+ /*
+ * To the console first, like supR3HardenedFatalV.
+ */
+ fprintf(stderr, "%s: Error %d in %s!\n", g_pszSupLibHardenedProgName, rc, pszWhere);
+ fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
+ va_list vaCopy;
+ va_copy(vaCopy, va);
+ vfprintf(stderr, pszMsgFmt, vaCopy);
+ va_end(vaCopy);
+ fprintf(stderr, "\n");
+
+ switch (enmWhat)
+ {
+ case kSupInitOp_Driver:
+ fprintf(stderr,
+ "\n"
+ "%s: Tip! Make sure the kernel module is loaded. It may also help to reinstall VirtualBox.\n",
+ g_pszSupLibHardenedProgName);
+ break;
+
+ case kSupInitOp_IPRT:
+ case kSupInitOp_Integrity:
+ case kSupInitOp_RootCheck:
+ fprintf(stderr,
+ "\n"
+ "%s: Tip! It may help to reinstall VirtualBox.\n",
+ g_pszSupLibHardenedProgName);
+ break;
+
+ default:
+ /* no hints here */
+ 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].
+ */
+ supR3HardenedMainDropPrivileges();
+#endif /* SUP_HARDENED_SUID */
+
+ /*
+ * 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 invovled with us).
+ */
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ int pid = fork();
+ if (pid <= 0)
+#endif
+ {
+ PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
+ if (pfnTrustedError)
+ pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
+ }
+
+ /*
+ * Quit
+ */
+ for (;;)
+#ifdef _MSC_VER
+ exit(1);
+#else
+ _Exit(1);
+#endif
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
+{
+ va_list va;
+ va_start(va, pszMsgFmt);
+ supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
+ va_end(va);
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
+{
+ fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
+ vfprintf(stderr, pszFormat, va);
+ for (;;)
+#ifdef _MSC_VER
+ exit(1);
+#else
+ _Exit(1);
+#endif
+}
+
+
+DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supR3HardenedFatalV(pszFormat, va);
+ va_end(va);
+}
+
+
+DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
+{
+ if (fFatal)
+ supR3HardenedFatalV(pszFormat, va);
+
+ fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
+ vfprintf(stderr, pszFormat, va);
+ return rc;
+}
+
+
+DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supR3HardenedErrorV(rc, fFatal, pszFormat, va);
+ va_end(va);
+ return rc;
+}
+
+
+/**
+ * Wrapper around snprintf which will throw a fatal error on buffer overflow.
+ *
+ * @returns Number of chars in the result string.
+ * @param pszDst The destination buffer.
+ * @param cchDst The size of the buffer.
+ * @param pszFormat The format string.
+ * @param ... Format arguments.
+ */
+static size_t supR3HardenedStrPrintf(char *pszDst, size_t cchDst, const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+#ifdef _MSC_VER
+ int cch = _vsnprintf(pszDst, cchDst, pszFormat, va);
+#else
+ int cch = vsnprintf(pszDst, cchDst, pszFormat, va);
+#endif
+ va_end(va);
+ if ((unsigned)cch >= cchDst || cch < 0)
+ supR3HardenedFatal("supR3HardenedStrPrintf: buffer overflow, %d >= %lu\n", cch, (long)cchDst);
+ return cch;
+}
+
+
+/**
+ * Attempts to open /dev/vboxdrv (or equvivalent).
+ *
+ * @remarks This function will not return on failure.
+ */
+static void supR3HardenedMainOpenDevice(void)
+{
+ int rc = suplibOsInit(&g_SupPreInitData.Data, false);
+ if (RT_SUCCESS(rc))
+ return;
+
+ switch (rc)
+ {
+ /** @todo better messages! */
+ case VERR_VM_DRIVER_NOT_INSTALLED:
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
+ "VERR_VM_DRIVER_NOT_INSTALLED");
+ case VERR_VM_DRIVER_NOT_ACCESSIBLE:
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
+ "VERR_VM_DRIVER_NOT_ACCESSIBLE");
+ case 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");
+ case VERR_VM_DRIVER_VERSION_MISMATCH:
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
+ "VERR_VM_DRIVER_VERSION_MISMATCH");
+ case VERR_ACCESS_DENIED:
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
+ "VERR_ACCESS_DENIED");
+ default:
+ supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
+ "Unknown rc=%d", rc);
+ }
+}
+
+
+#ifdef SUP_HARDENED_SUID
+
+/**
+ * Grabs extra non-root capabilities / privileges that we might require.
+ *
+ * This is currently only used for being able to do ICMP from the NAT engine.
+ *
+ * @note We still have root privileges at the time of this call.
+ */
+static void supR3HardenedMainGrabCapabilites(void)
+{
+# if defined(RT_OS_LINUX)
+ /*
+ * We are about to drop all our privileges. Remove all capabilities but
+ * keep the cap_net_raw capability for ICMP sockets for the NAT stack.
+ */
+ if (g_uCaps != 0)
+ {
+# ifdef USE_LIB_PCAP
+ /* XXX cap_net_bind_service */
+ if (!cap_set_proc(cap_from_text("all-eip cap_net_raw+ep")))
+ prctl(PR_SET_KEEPCAPS, /*keep=*/1, 0, 0, 0);
+# else
+ cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
+ cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->version = _LINUX_CAPABILITY_VERSION;
+ memset(cap, 0, sizeof(*cap));
+ cap->effective = g_uCaps;
+ cap->permitted = g_uCaps;
+ if (!capset(hdr, cap))
+ prctl(PR_SET_KEEPCAPS, /*keep=*/1, 0, 0, 0);
+# endif /* !USE_LIB_PCAP */
+ }
+
+# elif defined(RT_OS_SOLARIS)
+ /*
+ * Add net_icmpaccess privilege to permitted, effective and inheritable privileges
+ * before dropping root privileges.
+ */
+ priv_set_t *pPrivSet = priv_str_to_set("basic", ",", NULL);
+ if (pPrivSet)
+ {
+ priv_addset(pPrivSet, PRIV_NET_ICMPACCESS);
+ int rc = setppriv(PRIV_SET, PRIV_INHERITABLE, pPrivSet);
+ if (!rc)
+ {
+ rc = setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet);
+ if (!rc)
+ {
+ rc = setppriv(PRIV_SET, PRIV_EFFECTIVE, pPrivSet);
+ if (rc)
+ supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set effectives privilege set.\n");
+ }
+ else
+ supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set permitted privilege set.\n");
+ }
+ else
+ supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set inheritable privilege set.\n");
+
+ priv_freeset(pPrivSet);
+ }
+ else
+ supR3HardenedError(-1, false, "SUPR3HardenedMain: failed to get basic privilege set.\n");
+
+# endif
+}
+
+/*
+ * Look at the environment for some special options.
+ */
+static void supR3GrabOptions(void)
+{
+ const char *pszOpt;
+
+# ifdef RT_OS_LINUX
+ g_uCaps = 0;
+
+ /*
+ * Do _not_ perform any capability-related system calls for root processes
+ * (leaving g_uCaps at 0).
+ * (Hint: getuid gets the real user id, not the effective.)
+ */
+ if (getuid() != 0)
+ {
+ /*
+ * CAP_NET_RAW.
+ * Default: enabled.
+ * Can be disabled with 'export VBOX_HARD_CAP_NET_RAW=0'.
+ */
+ pszOpt = getenv("VBOX_HARD_CAP_NET_RAW");
+ if ( !pszOpt
+ || memcmp(pszOpt, "0", sizeof("0")) != 0)
+ g_uCaps = CAP_TO_MASK(CAP_NET_RAW);
+
+ /*
+ * CAP_NET_BIND_SERVICE.
+ * Default: disabled.
+ * Can be enabled with 'export VBOX_HARD_CAP_NET_BIND_SERVICE=1'.
+ */
+ pszOpt = getenv("VBOX_HARD_CAP_NET_BIND_SERVICE");
+ if ( pszOpt
+ && memcmp(pszOpt, "0", sizeof("0")) != 0)
+ g_uCaps |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ }
+# endif
+}
+
+/**
+ * Drop any root privileges we might be holding.
+ */
+static void supR3HardenedMainDropPrivileges(void)
+{
+ /*
+ * Try use setre[ug]id since this will clear the save uid/gid and thus
+ * leave fewer traces behind that libs like GTK+ may pick up.
+ */
+ uid_t euid, ruid, suid;
+ gid_t egid, rgid, sgid;
+# if defined(RT_OS_DARWIN)
+ /* The really great thing here is that setreuid isn't available on
+ OS X 10.4, libc emulates it. While 10.4 have a sligtly different and
+ non-standard setuid implementation compared to 10.5, the following
+ works the same way with both version since we're super user (10.5 req).
+ The following will set all three variants of the group and user IDs. */
+ setgid(g_gid);
+ setuid(g_uid);
+ euid = geteuid();
+ ruid = suid = getuid();
+ egid = getegid();
+ rgid = sgid = getgid();
+
+# elif defined(RT_OS_SOLARIS)
+ /* Solaris doesn't have setresuid, but the setreuid interface is BSD
+ compatible and will set the saved uid to euid when we pass it a ruid
+ that isn't -1 (which we do). */
+ setregid(g_gid, g_gid);
+ setreuid(g_uid, g_uid);
+ euid = geteuid();
+ ruid = suid = getuid();
+ egid = getegid();
+ rgid = sgid = getgid();
+
+# else
+ /* This is the preferred one, full control no questions about semantics.
+ PORTME: If this isn't work, try join one of two other gangs above. */
+ setresgid(g_gid, g_gid, g_gid);
+ setresuid(g_uid, g_uid, g_uid);
+ if (getresuid(&ruid, &euid, &suid) != 0)
+ {
+ euid = geteuid();
+ ruid = suid = getuid();
+ }
+ if (getresgid(&rgid, &egid, &sgid) != 0)
+ {
+ egid = getegid();
+ rgid = sgid = getgid();
+ }
+# endif
+
+
+ /* Check that it worked out all right. */
+ if ( euid != g_uid
+ || ruid != g_uid
+ || suid != g_uid
+ || egid != g_gid
+ || rgid != g_gid
+ || sgid != g_gid)
+ supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
+ " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
+ euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
+
+# if RT_OS_LINUX
+ /*
+ * Re-enable the cap_net_raw capability which was disabled during setresuid.
+ */
+ if (g_uCaps != 0)
+ {
+# ifdef USE_LIB_PCAP
+ /** @todo Warn if that does not work? */
+ /* XXX cap_net_bind_service */
+ cap_set_proc(cap_from_text("cap_net_raw+ep"));
+# else
+ cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
+ cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->version = _LINUX_CAPABILITY_VERSION;
+ memset(cap, 0, sizeof(*cap));
+ cap->effective = g_uCaps;
+ cap->permitted = g_uCaps;
+ /** @todo Warn if that does not work? */
+ capset(hdr, cap);
+# endif /* !USE_LIB_PCAP */
+ }
+# endif
+}
+
+#endif /* SUP_HARDENED_SUID */
+
+/**
+ * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
+ * and calls RTR3Init.
+ *
+ * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
+ *
+ * @remarks VBoxRT contains both IPRT and SUPR3.
+ * @remarks This function will not return on failure.
+ */
+static void supR3HardenedMainInitRuntime(uint32_t fFlags)
+{
+ /*
+ * Construct the name.
+ */
+ char szPath[RTPATH_MAX];
+ supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
+ strcat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
+
+ /*
+ * Open it and resolve the symbols.
+ */
+#if defined(RT_OS_WINDOWS)
+ /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
+ HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
+ if (!hMod)
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
+ "LoadLibraryEx(\"%s\",,) failed (rc=%d)",
+ szPath, GetLastError());
+ 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());
+
+ 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());
+
+#else
+ /* the dlopen crowd */
+ void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
+ if (!pvMod)
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
+ "dlopen(\"%s\",) failed: %s",
+ szPath, dlerror());
+ PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
+ if (!pfnRTInitEx)
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
+ "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
+ szPath, dlerror());
+ PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
+ if (!pfnSUPPreInit)
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
+ "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
+ szPath, dlerror());
+#endif
+
+ /*
+ * Make the calls.
+ */
+ supR3HardenedGetPreInitData(&g_SupPreInitData);
+ int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
+ if (RT_FAILURE(rc))
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
+ "supR3PreInit failed with rc=%d", rc);
+ const char *pszExePath = NULL;
+#ifdef RT_OS_LINUX
+ if (!supR3HardenedMainIsProcSelfExeAccssible())
+ pszExePath = g_szSupLibHardenedExePath;
+#endif
+ rc = pfnRTInitEx(0, pszExePath, !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV));
+ if (RT_FAILURE(rc))
+ supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
+ "RTR3Init failed with rc=%d", rc);
+}
+
+
+/**
+ * Loads the DLL/SO/DYLIB containing the actual program and
+ * resolves the TrustedError symbol.
+ *
+ * This is very similar to supR3HardenedMainGetTrustedMain().
+ *
+ * @returns Pointer to the trusted error symbol if it is exported, NULL
+ * and no error messages otherwise.
+ * @param pszProgName The program name.
+ */
+static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
+{
+ /*
+ * Construct the name.
+ */
+ char szPath[RTPATH_MAX];
+ supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
+ size_t cch = strlen(szPath);
+ supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
+
+ /*
+ * Open it and resolve the symbol.
+ */
+#if defined(RT_OS_WINDOWS)
+ /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
+ HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
+ if (!hMod)
+ return NULL;
+ FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
+ if (!pfn)
+ return NULL;
+ return (PFNSUPTRUSTEDERROR)pfn;
+
+#else
+ /* the dlopen crowd */
+ void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
+ if (!pvMod)
+ return NULL;
+ void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
+ if (!pvSym)
+ return NULL;
+ return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
+#endif
+}
+
+
+/**
+ * Loads the DLL/SO/DYLIB containing the actual program and
+ * resolves the TrustedMain symbol.
+ *
+ * @returns Pointer to the trusted main of the actual program.
+ * @param pszProgName The program name.
+ * @remarks This function will not return on failure.
+ */
+static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
+{
+ /*
+ * Construct the name.
+ */
+ char szPath[RTPATH_MAX];
+ supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
+ size_t cch = strlen(szPath);
+ supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
+
+ /*
+ * Open it and resolve the symbol.
+ */
+#if defined(RT_OS_WINDOWS)
+ /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
+ HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
+ if (!hMod)
+ supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibraryEx(\"%s\",,) failed, rc=%d\n",
+ szPath, GetLastError());
+ FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
+ if (!pfn)
+ supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
+ szPath, GetLastError());
+ return (PFNSUPTRUSTEDMAIN)pfn;
+
+#else
+ /* the dlopen crowd */
+ void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
+ if (!pvMod)
+ supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
+ szPath, dlerror());
+ void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
+ if (!pvSym)
+ supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
+ szPath, dlerror());
+ return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
+#endif
+}
+
+
+/**
+ * Secure main.
+ *
+ * This is used for the set-user-ID-on-execute binaries on unixy systems
+ * and when using the open-vboxdrv-via-root-service setup on Windows.
+ *
+ * This function will perform the integrity checks of the VirtualBox
+ * installation, open the support driver, open the root service (later),
+ * and load the DLL corresponding to \a pszProgName and execute its main
+ * function.
+ *
+ * @returns Return code appropriate for main().
+ *
+ * @param pszProgName The program name. This will be used to figure out which
+ * DLL/SO/DYLIB to load and execute.
+ * @param fFlags Flags.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param envp The environment vector.
+ */
+DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
+{
+ /*
+ * 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_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
+ g_SupPreInitData.Data.hDevice = NIL_RTFILE;
+ g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
+
+#ifdef SUP_HARDENED_SUID
+# ifdef RT_OS_LINUX
+ /*
+ * On linux we have to make sure the path is initialized because we
+ * *might* not be able to access /proc/self/exe after the seteuid call.
+ */
+ supR3HardenedGetFullExePath();
+
+# endif
+
+ /*
+ * Grab any options from the environment.
+ */
+ supR3GrabOptions();
+
+ /*
+ * Check that we're root, if we aren't then the installation is butchered.
+ */
+ g_uid = getuid();
+ g_gid = getgid();
+ if (geteuid() != 0 /* root */)
+ supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
+ "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
+ geteuid(), getegid(), g_uid, g_gid);
+#endif
+
+ /*
+ * Validate the installation.
+ */
+ supR3HardenedVerifyAll(true /* fFatal */, false /* fLeaveFilesOpen */, pszProgName);
+
+ /*
+ * Open the vboxdrv device.
+ */
+ if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
+ supR3HardenedMainOpenDevice();
+
+ /*
+ * Open the root service connection.
+ */
+ //if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_SVC))
+ //supR3HardenedMainOpenService(&g_SupPreInitData, true /* fFatal */);
+
+#ifdef SUP_HARDENED_SUID
+ /*
+ * Grab additional capabilities / privileges.
+ */
+ supR3HardenedMainGrabCapabilites();
+
+ /*
+ * Drop any root privileges we might be holding (won't return on failure)
+ */
+ supR3HardenedMainDropPrivileges();
+#endif
+
+ /*
+ * Load the IPRT, hand the SUPLib part the open driver and
+ * call RTR3Init.
+ */
+ supR3HardenedMainInitRuntime(fFlags);
+
+ /*
+ * Load the DLL/SO/DYLIB containing the actual program
+ * and pass control to it.
+ */
+ PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
+ return pfnTrustedMain(argc, argv, envp);
+}
+
+
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
new file mode 100644
index 000000000..5a6adf439
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
@@ -0,0 +1,810 @@
+/* $Id: SUPR3HardenedVerify.cpp 15353 2008-12-12 06:10:39Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Verification of Hardened Installation.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#if defined(RT_OS_OS2)
+# define INCL_BASE
+# define INCL_ERRORS
+# include <os2.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <sys/fcntl.h>
+# include <sys/errno.h>
+# include <sys/syslimits.h>
+
+#elif defined(RT_OS_WINDOWS)
+# include <Windows.h>
+# include <stdio.h>
+
+#else /* UNIXes */
+# include <sys/types.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <dlfcn.h>
+# include <fcntl.h>
+# include <limits.h>
+# include <errno.h>
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/fcntl.h>
+# include <stdio.h>
+# include <pwd.h>
+# ifdef RT_OS_DARWIN
+# include <mach-o/dyld.h>
+# endif
+
+#endif
+
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/string.h>
+#include <iprt/param.h>
+
+#include "SUPLibInternal.h"
+
+
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * The files that gets verified.
+ *
+ * @todo This needs reviewing against the linux packages.
+ * @todo The excessive use of kSupID_SharedLib needs to be reviewed at some point. For
+ * the time being we're building the linux packages with SharedLib pointing to
+ * AppPrivArch (lazy bird).
+ */
+static SUPINSTFILE const g_aSupInstallFiles[] =
+{
+ /* type, dir,fOptional, pszFile */
+ /* ---------------------------------------------------------------------- */
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VMMR0.r0" },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxDDR0.r0" },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxDD2R0.r0" },
+
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VMMGC.gc" },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxDDGC.gc" },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxDD2GC.gc" },
+
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxRT" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxVMM" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxREM" SUPLIB_DLL_SUFF },
+#if HC_ARCH_BITS == 32
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxREM32" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxREM64" SUPLIB_DLL_SUFF },
+#endif
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxDD" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxDD2" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxDDU" SUPLIB_DLL_SUFF },
+
+//#ifdef VBOX_WITH_DEBUGGER_GUI
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxDbg" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxDbg3" SUPLIB_DLL_SUFF },
+//#endif
+
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxSharedClipboard" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxSharedFolders" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxSharedCrOpenGL" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, false, "VBoxGuestPropSvc" SUPLIB_DLL_SUFF },
+
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxSharedCrOpenGL" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxOGLhostcrutil" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxOGLhosterrorspu" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxOGLrenderspu" SUPLIB_DLL_SUFF },
+
+ { kSupIFT_Exe, kSupID_AppBin, false, "VBoxManage" SUPLIB_EXE_SUFF },
+
+ { kSupIFT_Exe, kSupID_AppBin, false, "VBoxSVC" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxSettings" SUPLIB_DLL_SUFF },
+#ifdef RT_OS_WINDOWS
+ /** @todo */
+#else
+ { kSupIFT_Exe, kSupID_AppPrivArch, false, "VBoxXPCOMIPCD" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, false, "VBoxXPCOM" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArchComp, false, "VBoxXPCOMIPCC" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArchComp, false, "VBoxC" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArchComp, false, "VBoxSVCM" SUPLIB_DLL_SUFF },
+ { kSupIFT_Data, kSupID_AppPrivArchComp, false, "VBoxXPCOMBase.xpt" },
+#endif
+
+//#ifdef VBOX_WITH_VRDP
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VRDPAuth" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxVRDP" SUPLIB_DLL_SUFF },
+//#endif
+
+//#ifdef VBOX_WITH_HEADLESS
+ { kSupIFT_Exe, kSupID_AppBin, true, "VBoxHeadless" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxHeadless" SUPLIB_DLL_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxFFmpegFB" SUPLIB_DLL_SUFF },
+//#endif
+
+//#ifdef VBOX_WITH_QT4GUI
+ { kSupIFT_Exe, kSupID_AppBin, true, "VirtualBox" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VirtualBox" SUPLIB_DLL_SUFF },
+# if !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxKeyboard" SUPLIB_DLL_SUFF },
+# endif
+//#endif
+
+//#ifdef VBOX_WITH_QTGUI
+ { kSupIFT_Exe, kSupID_AppBin, true, "VirtualBox3" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VirtualBox3" SUPLIB_DLL_SUFF },
+# if !defined(RT_OS_DARWIN) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ { kSupIFT_Dll, kSupID_SharedLib, true, "VBoxKeyboard3" SUPLIB_DLL_SUFF },
+# endif
+//#endif
+
+//#ifdef VBOX_WITH_VBOXSDL
+ { kSupIFT_Exe, kSupID_AppBin, true, "VBoxSDL" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxSDL" SUPLIB_DLL_SUFF },
+//#endif
+
+//#ifdef VBOX_WITH_VBOXBFE
+ { kSupIFT_Exe, kSupID_AppBin, true, "VBoxBFE" SUPLIB_EXE_SUFF },
+ { kSupIFT_Dll, kSupID_AppPrivArch, true, "VBoxBFE" SUPLIB_DLL_SUFF },
+//#endif
+
+//#ifdef VBOX_WITH_WEBSERVICES
+ { kSupIFT_Exe, kSupID_AppBin, true, "vboxwebsrv" SUPLIB_EXE_SUFF },
+//#endif
+
+#ifdef RT_OS_LINUX
+ { kSupIFT_Exe, kSupID_AppBin, true, "VBoxTunctl" SUPLIB_EXE_SUFF },
+#endif
+};
+
+
+/** Array parallel to g_aSupInstallFiles containing per-file status info. */
+static SUPVERIFIEDFILE g_aSupVerifiedFiles[RT_ELEMENTS(g_aSupInstallFiles)];
+
+/** Array index by install directory specifier containing info about verified directories. */
+static SUPVERIFIEDDIR g_aSupVerifiedDirs[kSupID_End];
+
+
+/**
+ * Assembles the path to a dirtory.
+ *
+ * @returns VINF_SUCCESS on success, some error code on failure (fFatal
+ * decides whether it returns or not).
+ *
+ * @param enmDir The directory.
+ * @param pszDst Where to assemble the path.
+ * @param cchDst The size of the buffer.
+ * @param fFatal Whether failures should be treated as fatal (true) or not (false).
+ */
+static int supR3HardenedMakePath(SUPINSTDIR enmDir, char *pszDst, size_t cchDst, bool fFatal)
+{
+ int rc;
+ switch (enmDir)
+ {
+ case kSupID_AppBin: /** @todo fix this AppBin crap (uncertain wtf some binaries actually are installed). */
+ case kSupID_Bin:
+ rc = supR3HardenedPathProgram(pszDst, cchDst);
+ break;
+ case kSupID_SharedLib:
+ rc = supR3HardenedPathSharedLibs(pszDst, cchDst);
+ break;
+ case kSupID_AppPrivArch:
+ rc = supR3HardenedPathAppPrivateArch(pszDst, cchDst);
+ break;
+ case kSupID_AppPrivArchComp:
+ rc = supR3HardenedPathAppPrivateArch(pszDst, cchDst);
+ if (RT_SUCCESS(rc))
+ {
+ size_t off = strlen(pszDst);
+ if (cchDst - off >= sizeof("/components"))
+ memcpy(&pszDst[off], "/components", sizeof("/components"));
+ else
+ rc = VERR_BUFFER_OVERFLOW;
+ }
+ break;
+ case kSupID_AppPrivNoArch:
+ rc = supR3HardenedPathAppPrivateNoArch(pszDst, cchDst);
+ break;
+ default:
+ return supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedMakePath: enmDir=%d\n", enmDir);
+ }
+ if (RT_FAILURE(rc))
+ supR3HardenedError(rc, fFatal,
+ "supR3HardenedMakePath: enmDir=%d rc=%d\n", enmDir, rc);
+ return rc;
+}
+
+
+
+/**
+ * Assembles the path to a file table entry, with or without the actual filename.
+ *
+ * @returns VINF_SUCCESS on success, some error code on failure (fFatal
+ * decides whether it returns or not).
+ *
+ * @param pFile The file table entry.
+ * @param pszDst Where to assemble the path.
+ * @param cchDst The size of the buffer.
+ * @param fWithFilename If set, the filename is included, otherwise it is omitted (no trailing slash).
+ * @param fFatal Whether failures should be treated as fatal (true) or not (false).
+ */
+static int supR3HardenedMakeFilePath(PCSUPINSTFILE pFile, char *pszDst, size_t cchDst, bool fWithFilename, bool fFatal)
+{
+ /*
+ * Combine supR3HardenedMakePath and the filename.
+ */
+ int rc = supR3HardenedMakePath(pFile->enmDir, pszDst, cchDst, fFatal);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cchFile = strlen(pFile->pszFile);
+ size_t off = strlen(pszDst);
+ if (cchDst - off >= cchFile + 2)
+ {
+ pszDst[off++] = '/';
+ memcpy(&pszDst[off], pFile->pszFile, cchFile + 1);
+ }
+ else
+ rc = supR3HardenedError(VERR_BUFFER_OVERFLOW, fFatal,
+ "supR3HardenedMakeFilePath: pszFile=%s off=%lu\n",
+ pFile->pszFile, (long)off);
+ }
+ return rc;
+}
+
+
+/**
+ * Verifies a directory.
+ *
+ * @returns VINF_SUCCESS on success. On failure, an error code is returned if
+ * fFatal is clear and if it's set the function wont return.
+ * @param enmDir The directory specifier.
+ * @param fFatal Whether validation failures should be treated as
+ * fatal (true) or not (false).
+ */
+DECLHIDDEN(int) supR3HardenedVerifyDir(SUPINSTDIR enmDir, bool fFatal)
+{
+ /*
+ * Validate the index just to be on the safe side...
+ */
+ if (enmDir <= kSupID_Invalid || enmDir >= kSupID_End)
+ return supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedVerifyDir: enmDir=%d\n", enmDir);
+
+ /*
+ * Already validated?
+ */
+ if (g_aSupVerifiedDirs[enmDir].fValidated)
+ return VINF_SUCCESS; /** @todo revalidate? */
+
+ /* initialize the entry. */
+ if (g_aSupVerifiedDirs[enmDir].hDir != 0)
+ supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedVerifyDir: hDir=%p enmDir=%d\n",
+ (void *)g_aSupVerifiedDirs[enmDir].hDir, enmDir);
+ g_aSupVerifiedDirs[enmDir].hDir = -1;
+ g_aSupVerifiedDirs[enmDir].fValidated = false;
+
+ /*
+ * Make the path and open the directory.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = supR3HardenedMakePath(enmDir, szPath, sizeof(szPath), fFatal);
+ if (RT_SUCCESS(rc))
+ {
+#if defined(RT_OS_WINDOWS)
+ HANDLE hDir = CreateFile(szPath,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (hDir != INVALID_HANDLE_VALUE)
+ {
+ /** @todo check the type */
+ /* That's all on windows, for now at least... */
+ g_aSupVerifiedDirs[enmDir].hDir = (intptr_t)hDir;
+ g_aSupVerifiedDirs[enmDir].fValidated = true;
+ }
+ else
+ {
+ int err = GetLastError();
+ rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyDir: Failed to open \"%s\": err=%d\n",
+ szPath, err);
+ }
+#else /* UNIXY */
+ int fd = open(szPath, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ /*
+ * On unixy systems we'll make sure the directory is owned by root
+ * and not writable by the group and user.
+ */
+ struct stat st;
+ if (!fstat(fd, &st))
+ {
+
+ if ( st.st_uid == 0
+ && !(st.st_mode & (S_IWGRP | S_IWOTH))
+ && S_ISDIR(st.st_mode))
+ {
+ g_aSupVerifiedDirs[enmDir].hDir = fd;
+ g_aSupVerifiedDirs[enmDir].fValidated = true;
+ }
+ else
+ {
+ if (!S_ISDIR(st.st_mode))
+ rc = supR3HardenedError(VERR_NOT_A_DIRECTORY, fFatal,
+ "supR3HardenedVerifyDir: \"%s\" is not a directory\n",
+ szPath, (long)st.st_uid);
+ else if (st.st_uid)
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyDir: Cannot trust the directory \"%s\": not owned by root (st_uid=%ld)\n",
+ szPath, (long)st.st_uid);
+ else
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyDir: Cannot trust the directory \"%s\": group and/or other writable (st_mode=0%lo)\n",
+ szPath, (long)st.st_mode);
+ close(fd);
+ }
+ }
+ else
+ {
+ int err = errno;
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyDir: Failed to fstat \"%s\": %s (%d)\n",
+ szPath, strerror(err), err);
+ close(fd);
+ }
+ }
+ else
+ {
+ int err = errno;
+ rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyDir: Failed to open \"%s\": %s (%d)\n",
+ szPath, strerror(err), err);
+ }
+#endif /* UNIXY */
+ }
+
+ return rc;
+}
+
+
+/**
+ * Verifies a file entry.
+ *
+ * @returns VINF_SUCCESS on success. On failure, an error code is returned if
+ * fFatal is clear and if it's set the function wont return.
+ *
+ * @param iFile The file table index of the file to be verified.
+ * @param fFatal Whether validation failures should be treated as
+ * fatal (true) or not (false).
+ * @param fLeaveFileOpen Whether the file should be left open.
+ */
+static int supR3HardenedVerifyFileInternal(int iFile, bool fFatal, bool fLeaveFileOpen)
+{
+ PCSUPINSTFILE pFile = &g_aSupInstallFiles[iFile];
+ PSUPVERIFIEDFILE pVerified = &g_aSupVerifiedFiles[iFile];
+
+ /*
+ * Already done?
+ */
+ if (pVerified->fValidated)
+ return VINF_SUCCESS; /** @todo revalidate? */
+
+
+ /* initialize the entry. */
+ if (pVerified->hFile != 0)
+ supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedVerifyFileInternal: hFile=%p (%s)\n",
+ (void *)pVerified->hFile, pFile->pszFile);
+ pVerified->hFile = -1;
+ pVerified->fValidated = false;
+
+ /*
+ * Verify the directory then proceed to open it.
+ * (This'll make sure the directory is opened and that we can (later)
+ * use openat if we wish.)
+ */
+ int rc = supR3HardenedVerifyDir(pFile->enmDir, fFatal);
+ if (RT_SUCCESS(rc))
+ {
+ char szPath[RTPATH_MAX];
+ int rc = supR3HardenedMakeFilePath(pFile, szPath, sizeof(szPath), true, fFatal);
+ if (RT_SUCCESS(rc))
+ {
+#if defined(RT_OS_WINDOWS)
+ HANDLE hFile = CreateFile(szPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ /** @todo Check the type, and verify the signature (separate function so we can skip it). */
+ {
+ /* it's valid. */
+ if (fLeaveFileOpen)
+ pVerified->hFile = (intptr_t)hFile;
+ else
+ CloseHandle(hFile);
+ pVerified->fValidated = true;
+ }
+ }
+ else
+ {
+ int err = GetLastError();
+ if (!pFile->fOptional || err != ERROR_FILE_NOT_FOUND)
+ rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyFileInternal: Failed to open \"%s\": err=%d\n",
+ szPath, err);
+ }
+#else /* UNIXY */
+ int fd = open(szPath, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ /*
+ * On unixy systems we'll make sure the directory is owned by root
+ * and not writable by the group and user.
+ */
+ struct stat st;
+ if (!fstat(fd, &st))
+ {
+ if ( st.st_uid == 0
+ && !(st.st_mode & (S_IWGRP | S_IWOTH))
+ && S_ISREG(st.st_mode))
+ {
+ /* it's valid. */
+ if (fLeaveFileOpen)
+ pVerified->hFile = fd;
+ else
+ close(fd);
+ pVerified->fValidated = true;
+ }
+ else
+ {
+ if (!S_ISREG(st.st_mode))
+ rc = supR3HardenedError(VERR_IS_A_DIRECTORY, fFatal,
+ "supR3HardenedVerifyFileInternal: \"%s\" is not a regular file\n",
+ szPath, (long)st.st_uid);
+ else if (st.st_uid)
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyFileInternal: Cannot trust the file \"%s\": not owned by root (st_uid=%ld)\n",
+ szPath, (long)st.st_uid);
+ else
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyFileInternal: Cannot trust the file \"%s\": group and/or other writable (st_mode=0%lo)\n",
+ szPath, (long)st.st_mode);
+ close(fd);
+ }
+ }
+ else
+ {
+ int err = errno;
+ rc = supR3HardenedError(VERR_ACCESS_DENIED, fFatal,
+ "supR3HardenedVerifyFileInternal: Failed to fstat \"%s\": %s (%d)\n",
+ szPath, strerror(err), err);
+ close(fd);
+ }
+ }
+ else
+ {
+ int err = errno;
+ if (!pFile->fOptional || err != ENOENT)
+ rc = supR3HardenedError(VERR_PATH_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyFileInternal: Failed to open \"%s\": %s (%d)\n",
+ szPath, strerror(err), err);
+ }
+#endif /* UNIXY */
+ }
+ }
+
+ return rc;
+}
+
+
+/**
+ * Verifies that the specified table entry matches the given filename.
+ *
+ * @returns VINF_SUCCESS if matching. On mismatch fFatal indicates whether an
+ * error is returned or we terminate the application.
+ *
+ * @param iFile The file table index.
+ * @param pszFilename The filename.
+ * @param fFatal Whether validation failures should be treated as
+ * fatal (true) or not (false).
+ */
+static int supR3HardenedVerifySameFile(int iFile, const char *pszFilename, bool fFatal)
+{
+ PCSUPINSTFILE pFile = &g_aSupInstallFiles[iFile];
+
+ /*
+ * Construct the full path for the file table entry
+ * and compare it with the specified file.
+ */
+ char szName[RTPATH_MAX];
+ int rc = supR3HardenedMakeFilePath(pFile, szName, sizeof(szName), true /*fWithFilename*/, fFatal);
+ if (RT_FAILURE(rc))
+ return rc;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ if (stricmp(szName, pszFilename))
+#else
+ if (strcmp(szName, pszFilename))
+#endif
+ {
+ /*
+ * Normalize the two paths and compare again.
+ */
+ rc = VERR_NOT_SAME_DEVICE;
+#if defined(RT_OS_WINDOWS)
+ LPSTR pszIgnored;
+ char szName2[RTPATH_MAX];
+ if ( GetFullPathName(szName, RT_ELEMENTS(szName2), &szName2[0], &pszIgnored)
+ && GetFullPathName(pszFilename, RT_ELEMENTS(szName), &szName[0], &pszIgnored))
+ if (!stricmp(szName2, szName))
+ rc = VINF_SUCCESS;
+#else
+ AssertCompile(RTPATH_MAX >= PATH_MAX);
+ char szName2[RTPATH_MAX];
+ if ( realpath(szName, szName2) != NULL
+ && realpath(pszFilename, szName) != NULL)
+ if (!strcmp(szName2, szName))
+ rc = VINF_SUCCESS;
+#endif
+
+ if (RT_FAILURE(rc))
+ {
+ supR3HardenedMakeFilePath(pFile, szName, sizeof(szName), true /*fWithFilename*/, fFatal);
+ return supR3HardenedError(rc, fFatal,
+ "supR3HardenedVerifySameFile: \"%s\" isn't the same as \"%s\"\n",
+ pszFilename, szName);
+ }
+ }
+
+ /*
+ * Check more stuff like the stat info if it's an already open file?
+ */
+
+
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Verifies a file.
+ *
+ * @returns VINF_SUCCESS on success.
+ * VERR_NOT_FOUND if the file isn't in the table, this isn't ever a fatal error.
+ * On verfication failure, an error code will be returned when fFatal is clear,
+ * otherwise the program will be termindated.
+ *
+ * @param pszFilename The filename.
+ * @param fFatal Whether validation failures should be treated as
+ * fatal (true) or not (false).
+ */
+DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, bool fFatal)
+{
+ /*
+ * Lookup the file and check if it's the same file.
+ */
+ const char *pszName = supR3HardenedPathFilename(pszFilename);
+ for (unsigned iFile = 0; iFile < RT_ELEMENTS(g_aSupInstallFiles); iFile++)
+ if (!strcmp(pszName, g_aSupInstallFiles[iFile].pszFile))
+ {
+ int rc = supR3HardenedVerifySameFile(iFile, pszFilename, fFatal);
+ if (RT_SUCCESS(rc))
+ rc = supR3HardenedVerifyFileInternal(iFile, fFatal, false /* fLeaveFileOpen */);
+ return rc;
+ }
+
+ return VERR_NOT_FOUND;
+}
+
+
+/**
+ * Verifies a program, worker for supR3HardenedVerifyAll.
+ *
+ * @returns See supR3HardenedVerifyAll.
+ * @param pszProgName See supR3HardenedVerifyAll.
+ * @param fFatal See supR3HardenedVerifyAll.
+ */
+static int supR3HardenedVerifyProgram(const char *pszProgName, bool fFatal)
+{
+ /*
+ * Search the table looking for the executable and the DLL/DYLIB/SO.
+ */
+ int rc = VINF_SUCCESS;
+ bool fExe = false;
+ bool fDll = false;
+ size_t const cchProgName = strlen(pszProgName);
+ for (unsigned iFile = 0; iFile < RT_ELEMENTS(g_aSupInstallFiles); iFile++)
+ if (!strncmp(pszProgName, g_aSupInstallFiles[iFile].pszFile, cchProgName))
+ {
+ if ( g_aSupInstallFiles[iFile].enmType == kSupIFT_Dll
+ && !strcmp(&g_aSupInstallFiles[iFile].pszFile[cchProgName], SUPLIB_DLL_SUFF))
+ {
+ /* This only has to be found (once). */
+ if (fDll)
+ rc = supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedVerifyProgram: duplicate DLL entry for \"%s\"\n", pszProgName);
+ fDll = true;
+ }
+ else if ( g_aSupInstallFiles[iFile].enmType == kSupIFT_Exe
+ && !strcmp(&g_aSupInstallFiles[iFile].pszFile[cchProgName], SUPLIB_EXE_SUFF))
+ {
+ /* Here we'll have to check that the specific program is the same as the entry. */
+ if (fExe)
+ rc = supR3HardenedError(VERR_INTERNAL_ERROR, fFatal,
+ "supR3HardenedVerifyProgram: duplicate EXE entry for \"%s\"\n", pszProgName);
+ fExe = true;
+
+ char szFilename[RTPATH_MAX];
+ int rc2 = supR3HardenedPathProgram(szFilename, sizeof(szFilename) - cchProgName - sizeof(SUPLIB_EXE_SUFF));
+ if (RT_SUCCESS(rc2))
+ {
+ strcat(szFilename, "/");
+ strcat(szFilename, g_aSupInstallFiles[iFile].pszFile);
+ supR3HardenedVerifySameFile(iFile, szFilename, fFatal);
+ }
+ else
+ rc = supR3HardenedError(rc2, fFatal,
+ "supR3HardenedVerifyProgram: failed to query program path: rc=%d\n", rc2);
+ }
+ }
+
+ /*
+ * Check the findings.
+ */
+ if (!fDll && !fExe)
+ rc = supR3HardenedError(VERR_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyProgram: Couldn't find the program \"%s\"\n", pszProgName);
+ else if (!fExe)
+ rc = supR3HardenedError(VERR_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyProgram: Couldn't find the EXE entry for \"%s\"\n", pszProgName);
+ else if (!fDll)
+ rc = supR3HardenedError(VERR_NOT_FOUND, fFatal,
+ "supR3HardenedVerifyProgram: Couldn't find the DLL entry for \"%s\"\n", pszProgName);
+ return rc;
+}
+
+
+
+/**
+ * Verifies all the known files.
+ *
+ * @returns VINF_SUCCESS on success.
+ * On verfication failure, an error code will be returned when fFatal is clear,
+ * otherwise the program will be termindated.
+ *
+ * @param fFatal Whether validation failures should be treated as
+ * fatal (true) or not (false).
+ * @param fLeaveFilesOpen If set, all the verfied files are left open.
+ * @param pszProgName Optional program name. This is used by SUPR3HardenedMain
+ * to verify that both the executable and corresponding
+ * DLL/DYLIB/SO are valid.
+ */
+DECLHIDDEN(int) supR3HardenedVerifyAll(bool fFatal, bool fLeaveFilesOpen, const char *pszProgName)
+{
+ /*
+ * The verify all the files.
+ */
+ int rc = VINF_SUCCESS;
+ for (unsigned iFile = 0; iFile < RT_ELEMENTS(g_aSupInstallFiles); iFile++)
+ {
+ int rc2 = supR3HardenedVerifyFileInternal(iFile, fFatal, fLeaveFilesOpen);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ /*
+ * Verify the program name if specified, that is to say, just check that
+ * it's in the table (=> we've already verified it).
+ */
+ if (pszProgName)
+ {
+ int rc2 = supR3HardenedVerifyProgram(pszProgName, fFatal);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc2 = rc;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Gets the pre-init data for the hand-over to the other version
+ * of this code.
+ *
+ * The reason why we pass this information on is that it contains
+ * open directories and files. Later it may include even more info
+ * (int the verified arrays mostly).
+ *
+ * The receiver is supR3HardenedRecvPreInitData.
+ *
+ * @param pPreInitData Where to store it.
+ */
+DECLHIDDEN(void) supR3HardenedGetPreInitData(PSUPPREINITDATA pPreInitData)
+{
+ pPreInitData->cInstallFiles = RT_ELEMENTS(g_aSupInstallFiles);
+ pPreInitData->paInstallFiles = &g_aSupInstallFiles[0];
+ pPreInitData->paVerifiedFiles = &g_aSupVerifiedFiles[0];
+
+ pPreInitData->cVerifiedDirs = RT_ELEMENTS(g_aSupVerifiedDirs);
+ pPreInitData->paVerifiedDirs = &g_aSupVerifiedDirs[0];
+}
+
+
+/**
+ * Receives the pre-init data from the static executable stub.
+ *
+ * @returns VBox status code. Will not bitch on failure since the
+ * runtime isn't ready for it, so that is left to the exe stub.
+ *
+ * @param pPreInitData The hand-over data.
+ */
+DECLHIDDEN(int) supR3HardenedRecvPreInitData(PCSUPPREINITDATA pPreInitData)
+{
+ /*
+ * Compare the array lengths and the contents of g_aSupInstallFiles.
+ */
+ if ( pPreInitData->cInstallFiles != RT_ELEMENTS(g_aSupInstallFiles)
+ || pPreInitData->cVerifiedDirs != RT_ELEMENTS(g_aSupVerifiedDirs))
+ return VERR_VERSION_MISMATCH;
+ SUPINSTFILE const *paInstallFiles = pPreInitData->paInstallFiles;
+ for (unsigned iFile = 0; iFile < RT_ELEMENTS(g_aSupInstallFiles); iFile++)
+ if ( g_aSupInstallFiles[iFile].enmDir != paInstallFiles[iFile].enmDir
+ || g_aSupInstallFiles[iFile].enmType != paInstallFiles[iFile].enmType
+ || g_aSupInstallFiles[iFile].fOptional != paInstallFiles[iFile].fOptional
+ || strcmp(g_aSupInstallFiles[iFile].pszFile, paInstallFiles[iFile].pszFile))
+ return VERR_VERSION_MISMATCH;
+
+ /*
+ * Check that we're not called out of order.
+ * If dynamic linking it screwed up, we may end up here.
+ */
+ if ( ASMMemIsAll8(&g_aSupVerifiedFiles[0], sizeof(g_aSupVerifiedFiles), 0) != NULL
+ || ASMMemIsAll8(&g_aSupVerifiedDirs[0], sizeof(g_aSupVerifiedDirs), 0) != NULL)
+ return VERR_WRONG_ORDER;
+
+ /*
+ * Copy the verification data over.
+ */
+ memcpy(&g_aSupVerifiedFiles[0], pPreInitData->paVerifiedFiles, sizeof(g_aSupVerifiedFiles));
+ memcpy(&g_aSupVerifiedDirs[0], pPreInitData->paVerifiedDirs, sizeof(g_aSupVerifiedDirs));
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/HostDrivers/Support/SUPSvc.cpp b/src/VBox/HostDrivers/Support/SUPSvc.cpp
new file mode 100644
index 000000000..acf7ff293
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPSvc.cpp
@@ -0,0 +1,450 @@
+/* $Id: SUPSvc.cpp 11725 2008-08-27 22:21:47Z vboxsync $ */
+/** @file
+ * VirtualBox Support Service - Common Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include <VBox/log.h>
+#include <iprt/string.h>
+#include <iprt/mem.h>
+#include <iprt/stream.h>
+#include <iprt/getopt.h>
+
+#include "SUPSvcInternal.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Service state.
+ */
+typedef enum SUPSVCSERVICESTATE
+{
+ kSupSvcServiceState_Invalid = 0,
+ kSupSvcServiceState_NotCreated,
+ kSupSvcServiceState_Paused,
+ kSupSvcServiceState_Running,
+ kSupSvcServiceState_End
+} SUPSVCSERVICESTATE;
+
+
+/**
+ * Service descriptor.
+ */
+typedef struct SUPSVCSERVICE
+{
+ /** The service name. */
+ const char *pszName;
+ /** The service state. */
+ SUPSVCSERVICESTATE enmState;
+ /** The instance handle returned by pfnCreate. */
+ void *pvInstance;
+
+ /**
+ * Create the service (don't start it).
+ *
+ * @returns VBox status code, log entry is written on failure.
+ * @param ppvInstance Where to store the instance handle.
+ */
+ DECLCALLBACKMEMBER(int, pfnCreate)(void **ppvInstance);
+
+ /**
+ * Start the service.
+ *
+ * @returns VBox status code, log entry is written on failure.
+ * @param pvInstance The instance handle.
+ */
+ DECLCALLBACKMEMBER(void, pfnStart)(void *pvInstance);
+
+ /**
+ * Attempt to stop a running service.
+ *
+ * This should fail if there are active clients. A stopped service
+ * can be restarted by calling pfnStart.
+ *
+ * @returns VBox status code, log entry is written on failure.
+ * @param pvInstance The instance handle.
+ */
+ DECLCALLBACKMEMBER(int, pfnTryStop)(void *pvInstance);
+
+ /**
+ * Destroy the service, stopping first it if necessary.
+ *
+ * @param pvInstance The instance handle.
+ * @param fRunning Whether the service is running or not.
+ */
+ DECLCALLBACKMEMBER(void, pfnStopAndDestroy)(void *pvInstance, bool fRunning);
+} SUPSVCSERVICE;
+/** Pointer to a service descriptor. */
+typedef SUPSVCSERVICE *PSUPSVCSERVICE;
+/** Pointer to a const service descriptor. */
+typedef SUPSVCSERVICE const *PCSUPSVCSERVICE;
+
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+static SUPSVCSERVICE g_aServices[] =
+{
+ {
+ "Global",
+ kSupSvcServiceState_NotCreated,
+ NULL,
+ supSvcGlobalCreate,
+ supSvcGlobalStart,
+ supSvcGlobalTryStop,
+ supSvcGlobalStopAndDestroy,
+ }
+#ifdef RT_OS_WINDOWS
+ ,
+ {
+ "Grant",
+ kSupSvcServiceState_NotCreated,
+ NULL,
+ supSvcGrantCreate,
+ supSvcGrantStart,
+ supSvcGrantTryStop,
+ supSvcGrantStopAndDestroy,
+ }
+#endif
+};
+
+
+
+/**
+ * Instantiates and starts the services.
+ *
+ * @returns VBox status code. Done bitching on failure.
+ */
+int supSvcCreateAndStartServices(void)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Validate that all services are in the NotCreated state.
+ */
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
+ if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
+ {
+ supSvcLogError("service %s in state %d, expected state %d (NotCreated)",
+ g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
+ return VERR_WRONG_ORDER;
+ }
+
+ /*
+ * Create all the services, then start them.
+ */
+ int rc = VINF_SUCCESS;
+ for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
+ {
+ void *pvInstance = NULL;
+ int rc = g_aServices[i].pfnCreate(&pvInstance);
+ if (RT_FAILURE(rc))
+ {
+ Log(("supSvcCreateAndStartServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
+ break;
+ }
+ g_aServices[i].pvInstance = pvInstance;
+ g_aServices[i].enmState = kSupSvcServiceState_Paused;
+ }
+ if (RT_SUCCESS(rc))
+ {
+ for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
+ {
+ g_aServices[i].pfnStart(g_aServices[i].pvInstance);
+ g_aServices[i].enmState = kSupSvcServiceState_Running;
+ }
+ }
+ else
+ {
+ /*
+ * Destroy any services we managed to instantiate.
+ */
+ while (i-- > 0)
+ {
+ g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance, false /* fRunning */);
+ g_aServices[i].pvInstance = NULL;
+ g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
+ }
+ }
+
+ LogFlow(("supSvcCreateAndStartServices: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Checks if it's possible to stop the services.
+ *
+ * @returns VBox status code, done bitching on failure.
+ */
+int supSvcTryStopServices(void)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Check that the services are all created and count the running ones.
+ */
+ unsigned i;
+ unsigned cRunning = 0;
+ for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
+ if (g_aServices[i].enmState == kSupSvcServiceState_Running)
+ cRunning++;
+ else if (g_aServices[i].enmState == kSupSvcServiceState_NotCreated)
+ {
+ supSvcLogError("service %s in state %d (NotCreated), expected pause or running",
+ g_aServices[i].pszName, g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
+ return VERR_WRONG_ORDER;
+ }
+ if (!cRunning)
+ return VINF_SUCCESS; /* all stopped, nothing to do. */
+ Assert(cRunning == RT_ELEMENTS(g_aServices)); /* all or nothing */
+
+ /*
+ * Try stop them in reverse of start order.
+ */
+ int rc = VINF_SUCCESS;
+ i = RT_ELEMENTS(g_aServices);
+ while (i-- > 0)
+ {
+ rc = g_aServices[i].pfnTryStop(g_aServices[i].pvInstance);
+ if (RT_FAILURE(rc))
+ {
+ Log(("supSvcTryStopServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
+ break;
+ }
+ g_aServices[i].enmState = kSupSvcServiceState_Paused;
+ }
+ if (RT_FAILURE(rc))
+ {
+ /* Failed, restart the ones we succeeded in stopping. */
+ while (++i < RT_ELEMENTS(g_aServices))
+ {
+ g_aServices[i].pfnStart(g_aServices[i].pvInstance);
+ g_aServices[i].enmState = kSupSvcServiceState_Running;
+ }
+ }
+ LogFlow(("supSvcTryStopServices: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * Stops and destroys the services.
+ */
+void supSvcStopAndDestroyServices(void)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Stop and destroy the service in reverse of start order.
+ */
+ unsigned i = RT_ELEMENTS(g_aServices);
+ while (i-- > 0)
+ if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
+ {
+ g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance,
+ g_aServices[i].enmState == kSupSvcServiceState_Running);
+ g_aServices[i].pvInstance = NULL;
+ g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
+ }
+
+ LogFlowFuncLeave();
+}
+
+
+
+/**
+ * Logs the message to the appropirate system log.
+ *
+ * In debug builds this will also put it in the debug log.
+ *
+ * @param pszMsg The log string.
+ *
+ * @remarks This may later be replaced by the release logger and callback destination(s).
+ */
+void supSvcLogErrorStr(const char *pszMsg)
+{
+ supSvcOsLogErrorStr(pszMsg);
+ LogRel(("%s\n", pszMsg));
+}
+
+
+/**
+ * Logs the message to the appropirate system log.
+ *
+ * In debug builds this will also put it in the debug log.
+ *
+ * @param pszFormat The log string. No trailing newline.
+ * @param ... Format arguments.
+ *
+ * @todo This should later be replaced by the release logger and callback destination(s).
+ */
+void supSvcLogErrorV(const char *pszFormat, va_list va)
+{
+ if (*pszFormat)
+ {
+ char *pszMsg = NULL;
+ if (RTStrAPrintfV(&pszMsg, pszFormat, va) != -1)
+ {
+ supSvcLogErrorStr(pszMsg);
+ RTStrFree(pszMsg);
+ }
+ else
+ supSvcLogErrorStr(pszFormat);
+ }
+}
+
+
+/**
+ * Logs the error message to the appropirate system log.
+ *
+ * In debug builds this will also put it in the debug log.
+ *
+ * @param pszFormat The log string. No trailing newline.
+ * @param ... Format arguments.
+ *
+ * @todo This should later be replaced by the release logger and callback destination(s).
+ */
+void supSvcLogError(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supSvcLogErrorV(pszFormat, va);
+ va_end(va);
+}
+
+
+/**
+ * Deals with RTGetOpt failure, bitching in the system log.
+ *
+ * @returns 1
+ * @param pszAction The action name.
+ * @param rc The RTGetOpt return value.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param iArg The argument index.
+ * @param pValue The value returned by RTGetOpt.
+ */
+int supSvcLogGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
+{
+ supSvcLogError("%s - RTGetOpt failure, %Rrc (%d): %s",
+ pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
+ return 1;
+}
+
+
+/**
+ * Bitch about too many arguments (after RTGetOpt stops) in the system log.
+ *
+ * @returns 1
+ * @param pszAction The action name.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param iArg The argument index.
+ */
+int supSvcLogTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
+{
+ Assert(iArg < argc);
+ supSvcLogError("%s - Too many arguments: %s", pszAction, argv[iArg]);
+ for ( ; iArg < argc; iArg++)
+ LogRel(("arg#%i: %s\n", iArg, argv[iArg]));
+ return 1;
+}
+
+
+/**
+ * Prints an error message to the screen.
+ *
+ * @param pszFormat The message format string.
+ * @param va Format arguments.
+ */
+void supSvcDisplayErrorV(const char *pszFormat, va_list va)
+{
+ RTStrmPrintf(g_pStdErr, "VBoxSupSvc error: ");
+ RTStrmPrintfV(g_pStdErr, pszFormat, va);
+ Log(("supSvcDisplayErrorV: %s", pszFormat)); /** @todo format it! */
+}
+
+
+/**
+ * Prints an error message to the screen.
+ *
+ * @param pszFormat The message format string.
+ * @param ... Format arguments.
+ */
+void supSvcDisplayError(const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ supSvcDisplayErrorV(pszFormat, va);
+ va_end(va);
+}
+
+
+/**
+ * Deals with RTGetOpt failure.
+ *
+ * @returns 1
+ * @param pszAction The action name.
+ * @param rc The RTGetOpt return value.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param iArg The argument index.
+ * @param pValue The value returned by RTGetOpt.
+ */
+int supSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
+{
+ supSvcDisplayError("%s - RTGetOpt failure, %Rrc (%d): %s\n",
+ pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
+ return 1;
+}
+
+
+/**
+ * Bitch about too many arguments (after RTGetOpt stops).
+ *
+ * @returns 1
+ * @param pszAction The action name.
+ * @param argc The argument count.
+ * @param argv The argument vector.
+ * @param iArg The argument index.
+ */
+int supSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
+{
+ Assert(iArg < argc);
+ supSvcDisplayError("%s - Too many arguments: %s\n", pszAction, argv[iArg]);
+ return 1;
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPSvcGlobal.cpp b/src/VBox/HostDrivers/Support/SUPSvcGlobal.cpp
new file mode 100644
index 000000000..585a29377
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPSvcGlobal.cpp
@@ -0,0 +1,72 @@
+/* $Id: SUPSvcGlobal.cpp 11725 2008-08-27 22:21:47Z vboxsync $ */
+/** @file
+ * VirtualBox Support Service - The Global Service.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "SUPSvcInternal.h"
+
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+/** @copydoc SUPSVCSERVICE::pfnCreate */
+DECLCALLBACK(int) supSvcGlobalCreate(void **ppvInstance)
+{
+ *ppvInstance = (void *)1;
+ return VINF_SUCCESS;
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnStart */
+DECLCALLBACK(void) supSvcGlobalStart(void *pvInstance)
+{
+ Assert(pvInstance == (void *)1);
+ NOREF(pvInstance);
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnTryStop */
+DECLCALLBACK(int) supSvcGlobalTryStop(void *pvInstance)
+{
+ Assert(pvInstance == (void *)1);
+ NOREF(pvInstance);
+ return VINF_SUCCESS;
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnStopAndDestroy */
+DECLCALLBACK(void) supSvcGlobalStopAndDestroy(void *pvInstance, bool fRunning)
+{
+ Assert(pvInstance == (void *)1);
+ NOREF(pvInstance);
+ NOREF(fRunning);
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPSvcGrant.cpp b/src/VBox/HostDrivers/Support/SUPSvcGrant.cpp
new file mode 100644
index 000000000..ed05d64d8
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPSvcGrant.cpp
@@ -0,0 +1,1005 @@
+/* $Id: SUPSvcGrant.cpp 11725 2008-08-27 22:21:47Z vboxsync $ */
+/** @file
+ * VirtualBox Support Service - The Grant Service.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include "SUPSvcInternal.h"
+
+#include <VBox/log.h>
+#include <iprt/asm.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+#include <iprt/localipc.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** Pointer to a client instance. */
+typedef struct SUPSVCGRANTSESSION *PSUPSVCGRANTSESSION;
+/** Pointer to a Grant service instance. */
+typedef struct SUPSVCGRANT *PSUPSVCGRANT;
+
+
+/**
+ * Grant service session data.
+ */
+typedef struct SUPSVCGRANTSESSION
+{
+ /** Pointer to the next client in the list. */
+ PSUPSVCGRANTSESSION pNext;
+ /** Pointer to the previous client in the list. */
+ PSUPSVCGRANTSESSION pPrev;
+ /** Pointer to the parent (the service instance). */
+ PSUPSVCGRANT volatile pParent;
+ /** The local ipc client handle. */
+ RTLOCALIPCSESSION volatile hSession;
+ /** Indicate that the thread should terminate ASAP. */
+ bool volatile fTerminate;
+ /** The thread handle. */
+ RTTHREAD hThread;
+
+} SUPSVCGRANTSESSION;
+
+
+/**
+ * State grant service machine.
+ */
+typedef enum SUPSVCGRANTSTATE
+{
+ /** The invalid zero entry. */
+ kSupSvcGrantState_Invalid = 0,
+ /** Creating - the thread is being started.
+ * Next: Paused or Butchered. */
+ kSupSvcGrantState_Creating,
+ /** Paused - the thread is blocked on it's user event semaphore.
+ * Next: Resuming, Terminating or Butchered.
+ * Prev: Creating, Pausing */
+ kSupSvcGrantState_Paused,
+ /** Resuming - the thread is being unblocked and ushered into RTLocalIpcServiceListen.
+ * Next: Listen or Butchered.
+ * Prev: Paused */
+ kSupSvcGrantState_Resuming,
+ /** Listen - the thread is in RTLocalIpcServerListen or setting up an incoming session.
+ * Next: Pausing or Butchered.
+ * Prev: Resuming */
+ kSupSvcGrantState_Listen,
+ /** Pausing - Cancelling the listen and dropping any incoming sessions.
+ * Next: Paused or Butchered.
+ * Prev: Listen */
+ kSupSvcGrantState_Pausing,
+ /** Butchered - The thread has quit because something when terribly wrong.
+ * Next: Destroyed
+ * Prev: Any. */
+ kSupSvcGrantState_Butchered,
+ /** Pausing - Cancelling the listen and dropping any incoming sessions.
+ * Next: Destroyed
+ * Prev: Paused */
+ kSupSvcGrantState_Terminating,
+ /** Destroyed - the instance is invalid.
+ * Prev: Butchered or Terminating */
+ kSupSvcGrantState_Destroyed,
+ /** The end of valid state values. */
+ kSupSvcGrantState_End,
+ /** The usual 32-bit blowup hack. */
+ kSupSvcGrantState_32BitHack = 0x7fffffff
+} SUPSVCGRANTSTATE;
+
+
+/**
+ * Grant service instance data.
+ */
+typedef struct SUPSVCGRANT
+{
+ /** The local ipc server handle. */
+ RTLOCALIPCSERVER hServer;
+
+ /** Critical section serializing access to the session list, the state,
+ * the response event, the session event, and the thread event. */
+ RTCRITSECT CritSect;
+ /** The service thread will signal this event when it has changed to
+ * the 'paused' or 'running' state. */
+ RTSEMEVENT hResponseEvent;
+ /** Event that's signaled on session termination. */
+ RTSEMEVENT hSessionEvent;
+ /** The handle to the service thread. */
+ RTTHREAD hThread;
+ /** Head of the session list. */
+ PSUPSVCGRANTSESSION volatile pSessionHead;
+ /** The service state. */
+ SUPSVCGRANTSTATE volatile enmState;
+
+ /** Critical section serializing access to the SUPR3HardenedVerify APIs. */
+ RTCRITSECT VerifyCritSect;
+} SUPSVCGRANT;
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState);
+
+
+
+
+/**
+ * Services a client session.
+ *
+ * @returns VINF_SUCCESS.
+ *
+ * @param hThread The thread handle.
+ * @param pvSession Pointer to the session instance data.
+ */
+static DECLCALLBACK(int) supSvcGrantSessionThread(RTTHREAD hThread, void *pvSession)
+{
+ PSUPSVCGRANTSESSION pThis = (PSUPSVCGRANTSESSION)pvSession;
+ RTLOCALIPCSESSION hSession = pThis->hSession;
+ Log(("supSvcGrantSessionThread(%p):\n", pThis));
+
+ /*
+ * Process client requests untill it quits or we're cancelled on termination.
+ */
+ while (!ASMAtomicUoReadBool(&pThis->fTerminate))
+ {
+ RTThreadSleep(1000);
+ /** @todo */
+ }
+
+ /*
+ * Clean up the session.
+ */
+ PSUPSVCGRANT pParent = (PSUPSVCGRANT)ASMAtomicReadPtr((void * volatile *)&pThis->pParent);
+ if (pParent)
+ RTCritSectEnter(&pParent->CritSect);
+ else
+ Log(("supSvcGrantSessionThread(%p): No parent\n", pThis));
+
+ ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
+ if (hSession != NIL_RTLOCALIPCSESSION)
+ RTLocalIpcSessionClose(hSession);
+ else
+ Log(("supSvcGrantSessionThread(%p): No session handle\n", pThis));
+
+ if (pParent)
+ {
+ RTSemEventSignal(pParent->hSessionEvent);
+ RTCritSectLeave(&pParent->CritSect);
+ }
+ Log(("supSvcGrantSessionThread(%p): exits\n"));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Cleans up a session.
+ *
+ * This is called while inside the grant service critical section.
+ *
+ * @param pThis The session to destroy.
+ * @param pParent The parent.
+ */
+static void supSvcGrantSessionDestroy(PSUPSVCGRANTSESSION pThis, PSUPSVCGRANT pParent)
+{
+ /*
+ * Unlink it.
+ */
+ if (pThis->pNext)
+ {
+ Assert(pThis->pNext->pPrev == pThis);
+ pThis->pNext->pPrev = pThis->pPrev;
+ }
+
+ if (pThis->pPrev)
+ {
+ Assert(pThis->pPrev->pNext == pThis);
+ pThis->pPrev->pNext = pThis->pNext;
+ }
+ else if (pParent->pSessionHead == pThis)
+ pParent->pSessionHead = pThis->pNext;
+
+ /*
+ * Free the resources associated with it.
+ */
+ pThis->hThread = NIL_RTTHREAD;
+ pThis->pNext = NULL;
+ pThis->pPrev = NULL;
+
+ RTLOCALIPCSESSION hSession;
+ ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
+ if (hSession != NIL_RTLOCALIPCSESSION)
+ RTLocalIpcSessionClose(hSession);
+
+ RTMemFree(pThis);
+}
+
+
+/**
+ * Cleans up zombie sessions, locked.
+ *
+ * @param pThis Pointer to the grant service instance data.
+ */
+static void supSvcGrantCleanUpSessionsLocked(PSUPSVCGRANT pThis)
+{
+ /*
+ * Iterate untill be make it all the way thru the list.
+ *
+ * Only use the thread state as and indicator on whether we can destroy
+ * the session or not.
+ */
+ PSUPSVCGRANTSESSION pCur;
+ do
+ {
+ for (pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ {
+ int rc = RTThreadWait(pCur->hThread, 0, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ supSvcGrantSessionDestroy(pCur, pThis);
+ break;
+ }
+
+ Assert(rc == VERR_TIMEOUT);
+ Assert(pCur->hThread != NIL_RTTHREAD);
+ Assert(pCur->pNext != pThis->pSessionHead);
+ }
+ } while (pCur);
+}
+
+
+/**
+ * Cleans up zombie sessions.
+ *
+ * @returns VINF_SUCCESS, VBox error code on internal error.
+ *
+ * @param pThis Pointer to the grant service instance data.
+ * @param fOwnCritSect Whether we own the crit sect already. The state is preserved.
+ */
+static int supSvcGrantCleanUpSessions(PSUPSVCGRANT pThis, bool fOwnCritSect)
+{
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ {
+ supSvcLogError("supSvcGrantCleanUpSessions: RTCritSectEnter returns %Rrc", rc);
+ return rc;
+ }
+
+ supSvcGrantCleanUpSessionsLocked(pThis);
+
+ RTCritSectLeave(&pThis->CritSect);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Gets the state name.
+ *
+ * @returns The state name string (read only).
+ * @param enmState The state.
+ */
+static const char *supSvcGrantStateName(SUPSVCGRANTSTATE enmState)
+{
+ switch (enmState)
+ {
+ case kSupSvcGrantState_Invalid: return "Invalid";
+ case kSupSvcGrantState_Creating: return "Creating";
+ case kSupSvcGrantState_Paused: return "Paused";
+ case kSupSvcGrantState_Resuming: return "Resuming";
+ case kSupSvcGrantState_Listen: return "Listen";
+ case kSupSvcGrantState_Pausing: return "Pausing";
+ case kSupSvcGrantState_Butchered: return "Butchered";
+ case kSupSvcGrantState_Terminating: return "Terminating";
+ case kSupSvcGrantState_Destroyed: return "Destroyed";
+ default: return "?Unknown?";
+ }
+}
+
+
+/**
+ * Attempts to flip into the butchered state.
+ *
+ * @returns rc.
+ * @param pThis The instance data.
+ * @param fOwnCritSect Whether we own the crit sect already.
+ * @param pszFailed What failed.
+ * @param rc What to return (lazy bird).
+ */
+static int supSvcGrantThreadButchered(PSUPSVCGRANT pThis, bool fOwnCritSect, const char *pszFailed, int rc)
+{
+ int rc2 = VINF_SUCCESS;
+ if (!fOwnCritSect)
+ rc2 = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc2))
+ {
+ supSvcLogError("supSvcGrantThread(%s): Butchered; %Rrc: %s",
+ supSvcGrantStateName(pThis->enmState), rc, pszFailed);
+ pThis->enmState = kSupSvcGrantState_Butchered;
+
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ return rc;
+}
+
+
+/**
+ * Creates a new session.
+ *
+ * @returns VINF_SUCCESS on success, VBox error code on internal error.
+ *
+ * @param pThis Pointer to the grant service instance data.
+ * @param hSession The client session handle.
+ */
+static int supSvcGrantThreadCreateSession(PSUPSVCGRANT pThis, RTLOCALIPCSESSION hSession)
+{
+ /*
+ * Allocate and initialize a new session instance before entering the critsect.
+ */
+ PSUPSVCGRANTSESSION pSession = (PSUPSVCGRANTSESSION)RTMemAlloc(sizeof(*pSession));
+ if (!pSession)
+ {
+ supSvcLogError("supSvcGrantThreadListen: failed to allocate session");
+ return VINF_SUCCESS; /* not fatal? */
+ }
+ pSession->pPrev = NULL;
+ pSession->pNext = NULL;
+ pSession->pParent = pThis;
+ pSession->hSession = hSession;
+ pSession->fTerminate = false;
+ pSession->hThread = NIL_RTTHREAD;
+
+ /*
+ * Enter the critsect, check the state, link it and fire off the session thread.
+ */
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /* check the state */
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ if (enmState == kSupSvcGrantState_Listen)
+ {
+ /* link it */
+ pSession->pNext = pThis->pSessionHead;
+ if (pThis->pSessionHead)
+ pThis->pSessionHead->pPrev = pSession;
+ pThis->pSessionHead = pSession;
+
+ /* fire up the thread */
+ Log(("supSvcGrantThreadListen: starting session %p\n", pSession));
+ rc = RTThreadCreate(&pSession->hThread, supSvcGrantSessionThread, pSession, 0,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "SESSION");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectLeave(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectLeave", rc);
+
+ /*
+ * Successfully handled the client.
+ */
+ return VINF_SUCCESS;
+ }
+
+ /* bail out */
+ supSvcLogError("supSvcGrantThreadListen: RTThreadCreate returns %Rrc", rc);
+ }
+ else
+ Log(("supSvcGrantThreadListen: dropping connection, state %s\n", supSvcGrantStateName(enmState)));
+
+ RTCritSectLeave(&pThis->CritSect);
+ rc = VINF_SUCCESS;
+ }
+ else
+ supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTCritSectEnter", rc);
+ RTLocalIpcSessionClose(hSession);
+ RTMemFree(pSession);
+ return rc;
+}
+
+
+/**
+ * Listen for a client session and kicks off the service thread for it.
+ *
+ * @returns VINF_SUCCESS on normal state change, failure if something gets screwed up.
+ *
+ * @param pThis Pointer to the grant service instance data.
+ */
+static int supSvcGrantThreadListen(PSUPSVCGRANT pThis)
+{
+ /*
+ * Wait for a client to connect and create a new session.
+ */
+ RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
+ int rc = RTLocalIpcServerListen(pThis->hServer, &hClientSession);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CANCELLED)
+ LogFlow(("supSvcGrantThreadListen: cancelled\n"));
+ else if (rc == VERR_TRY_AGAIN)
+ /* for testing */;
+ else
+ return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "RTLocalIpcServerListen", rc);
+ return VINF_SUCCESS;
+ }
+
+ return supSvcGrantThreadCreateSession(pThis, hClientSession);
+}
+
+
+/**
+ * Grant service thread.
+ *
+ * This thread is the one listening for clients and kicks off
+ * the session threads and stuff.
+ *
+ * @returns VINF_SUCCESS on normal exit, VBox error status on failure.
+ * @param hThread The thread handle.
+ * @param pvThis Pointer to the grant service instance data.
+ */
+static DECLCALLBACK(int) supSvcGrantThread(RTTHREAD hThread, void *pvThis)
+{
+ PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvThis;
+
+ /*
+ * The state loop.
+ */
+ for (;;)
+ {
+ /*
+ * Switch on the current state (requires critsect).
+ */
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ {
+ supSvcLogError("supSvcGrantThread - RTCritSectEnter returns %Rrc", rc);
+ return rc;
+ }
+
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ LogFlow(("supSvcGrantThread: switching %s\n", supSvcGrantStateName(enmState)));
+ switch (enmState)
+ {
+ case kSupSvcGrantState_Creating:
+ case kSupSvcGrantState_Pausing:
+ pThis->enmState = kSupSvcGrantState_Paused;
+ rc = RTSemEventSignal(pThis->hResponseEvent);
+ if (RT_FAILURE(rc))
+ return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
+ /* fall thru */
+
+ case kSupSvcGrantState_Paused:
+ RTCritSectLeave(&pThis->CritSect);
+
+ rc = RTThreadUserWait(hThread, 60*1000); /* wake up once in a while (paranoia) */
+ if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
+ return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect*/, "RTThreadUserWait", rc);
+ break;
+
+ case kSupSvcGrantState_Resuming:
+ pThis->enmState = kSupSvcGrantState_Listen;
+ rc = RTSemEventSignal(pThis->hResponseEvent);
+ if (RT_FAILURE(rc))
+ return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "RTSemEventSignal", rc);
+ /* fall thru */
+
+ case kSupSvcGrantState_Listen:
+ RTCritSectLeave(&pThis->CritSect);
+ rc = supSvcGrantThreadListen(pThis);
+ if (RT_FAILURE(rc))
+ {
+ Log(("supSvcGrantThread: supSvcGrantDoListening returns %Rrc, exiting\n", rc));
+ return rc;
+ }
+ break;
+
+ case kSupSvcGrantState_Terminating:
+ RTCritSectLeave(&pThis->CritSect);
+ Log(("supSvcGrantThread: Done\n"));
+ return VINF_SUCCESS;
+
+ case kSupSvcGrantState_Butchered:
+ default:
+ return supSvcGrantThreadButchered(pThis, true /* fOwnCritSect*/, "Bad state", VERR_INTERNAL_ERROR);
+ }
+
+ /*
+ * Massage the session list between clients and states.
+ */
+ rc = supSvcGrantCleanUpSessions(pThis, false /* fOwnCritSect */);
+ if (RT_FAILURE(rc))
+ return supSvcGrantThreadButchered(pThis, false /* fOwnCritSect */, "supSvcGrantCleanUpSessions", rc);
+ }
+}
+
+
+/**
+ * Waits for the service thread to respond to a state change.
+ *
+ * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time, other error code on internal error.
+ *
+ * @param pThis Pointer to the grant service instance data.
+ * @param enmCurState The current state.
+ * @param enmNewState The new state we're waiting for it to enter.
+ */
+static int supSvcGrantWait(PSUPSVCGRANT pThis, SUPSVCGRANTSTATE enmCurState, SUPSVCGRANTSTATE enmNewState)
+{
+ LogFlow(("supSvcGrantWait(,%s,%s): enter\n",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState)));
+
+ /*
+ * Wait a short while for the response event to be set.
+ */
+ RTSemEventWait(pThis->hResponseEvent, 1000);
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ if (pThis->enmState == enmNewState)
+ {
+ RTCritSectLeave(&pThis->CritSect);
+ rc = VINF_SUCCESS;
+ }
+ else if (pThis->enmState == enmCurState)
+ {
+ /*
+ * Wait good while longer.
+ */
+ RTCritSectLeave(&pThis->CritSect);
+ rc = RTSemEventWait(pThis->hResponseEvent, 59*1000); /* 59 sec */
+ if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT)
+ {
+ rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Check the state whether we've succeeded.
+ */
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ if (enmState == enmNewState)
+ rc = VINF_SUCCESS;
+ else if (enmState == enmCurState)
+ {
+ supSvcLogError("supSvcGrantWait(,%s,%s) - the thread doesn't respond in a timely manner, failing.",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
+ rc = VERR_TIMEOUT;
+ }
+ else
+ {
+ supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
+ supSvcGrantStateName(enmNewState), supSvcGrantStateName(enmState));
+ AssertMsgFailed(("%s\n", supSvcGrantStateName(enmState)));
+ rc = VERR_INTERNAL_ERROR;
+ }
+
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ else
+ supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
+ }
+ else
+ supSvcLogError("supSvcGrantWait(,%s,%s) - RTSemEventWait returns %Rrc",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
+ }
+ else
+ {
+ supSvcLogError("supSvcGrantWait(,%s,%s) - wrong state %s!", supSvcGrantStateName(enmCurState),
+ supSvcGrantStateName(enmNewState), supSvcGrantStateName(pThis->enmState));
+ AssertMsgFailed(("%s\n", supSvcGrantStateName(pThis->enmState)));
+ RTCritSectLeave(&pThis->CritSect);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ }
+ else
+ supSvcLogError("supSvcGrantWait(,%s,%s) - RTCritSectEnter returns %Rrc",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState));
+
+ Log(("supSvcGrantWait(,%s,%s): returns %Rrc\n",
+ supSvcGrantStateName(enmCurState), supSvcGrantStateName(enmNewState), rc));
+ return rc;
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnCreate */
+DECLCALLBACK(int) supSvcGrantCreate(void **ppvInstance)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Allocate and initialize the session data.
+ */
+ PSUPSVCGRANT pThis = (PSUPSVCGRANT)RTMemAlloc(sizeof(*pThis));
+ if (!pThis)
+ {
+ supSvcLogError("supSvcGrantCreate - no memory");
+ return VERR_NO_MEMORY;
+ }
+ bool fFreeIt = true;
+ pThis->pSessionHead = NULL;
+ pThis->enmState = kSupSvcGrantState_Creating;
+ int rc = RTCritSectInit(&pThis->VerifyCritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pThis->hResponseEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pThis->hSessionEvent);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Create the local IPC instance and then finally fire up the thread.
+ */
+ rc = RTLocalIpcServerCreate(&pThis->hServer, SUPSVC_GRANT_SERVICE_NAME, RTLOCALIPC_FLAGS_MULTI_SESSION);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreate(&pThis->hThread, supSvcGrantThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "GRANT");
+ if (RT_SUCCESS(rc))
+ {
+ rc = supSvcGrantWait(pThis, kSupSvcGrantState_Creating, kSupSvcGrantState_Paused);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Successfully created the grant service!
+ */
+ Log(("supSvcGrantCreate: returns VINF_SUCCESS (pThis=%p)\n", pThis));
+ *ppvInstance = pThis;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * The thread FAILED to start in a timely manner!
+ */
+ RTCritSectEnter(&pThis->CritSect);
+ pThis->enmState = kSupSvcGrantState_Terminating;
+ RTCritSectLeave(&pThis->CritSect);
+
+ RTThreadUserSignal(pThis->hThread);
+
+ int cTries = 10;
+ int rc2 = RTThreadWait(pThis->hThread, 20000, NULL);
+ if (RT_FAILURE(rc2))
+ {
+ /* poke it a few more times before giving up. */
+ while (--cTries > 0)
+ {
+ RTThreadUserSignal(pThis->hThread);
+ RTLocalIpcServerCancel(pThis->hServer);
+ if (RTThreadWait(pThis->hThread, 1000, NULL) != VERR_TIMEOUT)
+ break;
+ }
+ }
+ fFreeIt = cTries <= 0;
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTThreadCreate returns %Rrc", rc);
+ RTLocalIpcServerDestroy(pThis->hServer);
+ pThis->hServer = NIL_RTLOCALIPCSERVER;
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTLocalIpcServiceCreate returns %Rrc", rc);
+ RTSemEventDestroy(pThis->hSessionEvent);
+ pThis->hSessionEvent = NIL_RTSEMEVENT;
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
+ RTSemEventDestroy(pThis->hResponseEvent);
+ pThis->hResponseEvent = NIL_RTSEMEVENT;
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTSemEventCreate returns %Rrc", rc);
+ RTCritSectDelete(&pThis->CritSect);
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
+ RTCritSectDelete(&pThis->VerifyCritSect);
+ }
+ else
+ supSvcLogError("supSvcGrantCreate - RTCritSectInit returns %Rrc", rc);
+ if (fFreeIt)
+ RTMemFree(pThis);
+ Log(("supSvcGrantCreate: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnStart */
+DECLCALLBACK(void) supSvcGrantStart(void *pvInstance)
+{
+ PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
+
+ /*
+ * Change the state and signal the thread.
+ */
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ bool fInCritSect = true;
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ if (enmState == kSupSvcGrantState_Paused)
+ {
+ pThis->enmState = kSupSvcGrantState_Resuming;
+ rc = RTThreadUserSignal(pThis->hThread);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Wait for the bugger to respond (no need to bitch here).
+ */
+ RTCritSectLeave(&pThis->CritSect);
+ supSvcGrantWait(pThis, kSupSvcGrantState_Resuming, kSupSvcGrantState_Listen);
+ fInCritSect = false;
+ }
+ }
+ else
+ supSvcLogError("supSvcGrantStart - Incorrect state %s!", supSvcGrantStateName(enmState));
+ if (fInCritSect)
+ RTCritSectLeave(&pThis->CritSect);
+ }
+ else
+ {
+ supSvcLogError("supSvcGrantStart - RTCritSectEnter returns %Rrc!", rc);
+ AssertRCReturnVoid(rc);
+ }
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnTryStop */
+DECLCALLBACK(int) supSvcGrantTryStop(void *pvInstance)
+{
+ PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
+
+ /*
+ * Don't give up immediately.
+ */
+ uint64_t u64StartTS = RTTimeMilliTS();
+ int rc;
+ for (;;)
+ {
+ /*
+ * First check the state to make sure the thing is actually running.
+ * If the critsect is butchered, just pretend success.
+ */
+ rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ {
+ supSvcLogError("supSvcGrantTryStop - RTCritSectEnter returns %Rrc", rc);
+ AssertRC(rc);
+ return VINF_SUCCESS;
+ }
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ if (enmState != kSupSvcGrantState_Listen)
+ {
+ supSvcLogError("supSvcGrantTryStop - Not running, state: %s", supSvcGrantStateName(enmState));
+ RTCritSectLeave(&pThis->CritSect);
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * If there are no clients, usher the thread into the paused state.
+ */
+ supSvcGrantCleanUpSessionsLocked(pThis);
+ if (!pThis->pSessionHead)
+ {
+ rc = RTThreadUserReset(pThis->hThread);
+ pThis->enmState = kSupSvcGrantState_Pausing;
+ int rc2 = RTLocalIpcServerCancel(pThis->hServer);
+ int rc3 = RTCritSectLeave(&pThis->CritSect);
+ if (RT_SUCCESS(rc) && RT_SUCCESS(rc2) && RT_SUCCESS(rc3))
+ supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
+ else
+ {
+ if (RT_FAILURE(rc))
+ supSvcLogError("supSvcGrantTryStop - RTThreadUserReset returns %Rrc", rc);
+ if (RT_FAILURE(rc2))
+ supSvcLogError("supSvcGrantTryStop - RTLocalIpcServerCancel returns %Rrc", rc);
+ if (RT_FAILURE(rc3))
+ supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
+ }
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Check the time limit, otherwise wait for a client event.
+ */
+ uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
+ if (u64Elapsed >= 60*1000) /* 1 min */
+ {
+ unsigned cSessions = 0;
+ for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ cSessions++;
+ RTCritSectLeave(&pThis->CritSect);
+
+ supSvcLogError("supSvcGrantTryStop - %u active sessions after waiting %u ms", cSessions, (unsigned)u64Elapsed);
+ return VERR_TRY_AGAIN;
+ }
+
+ rc = RTCritSectLeave(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ {
+ supSvcLogError("supSvcGrantTryStop - RTCritSectLeave returns %Rrc", rc);
+ return VINF_SUCCESS;
+ }
+
+ rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
+ if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
+ {
+ supSvcLogError("supSvcGrantTryStop - RTSemEventWait returns %Rrc", rc);
+ return VINF_SUCCESS;
+ }
+ }
+}
+
+
+/** @copydoc SUPSVCSERVICE::pfnStopAndDestroy */
+DECLCALLBACK(void) supSvcGrantStopAndDestroy(void *pvInstance, bool fRunning)
+{
+ PSUPSVCGRANT pThis = (PSUPSVCGRANT)pvInstance;
+ int rc;
+
+ /*
+ * Attempt to stop the service, cancelling blocked server and client calls.
+ */
+ RTCritSectEnter(&pThis->CritSect);
+
+ SUPSVCGRANTSTATE enmState = pThis->enmState;
+ AssertMsg(fRunning == (pThis->enmState == kSupSvcGrantState_Listen),
+ ("%RTbool %s\n", fRunning, supSvcGrantStateName(enmState)));
+
+ if (enmState == kSupSvcGrantState_Listen)
+ {
+ RTThreadUserReset(pThis->hThread);
+ pThis->enmState = kSupSvcGrantState_Paused;
+ for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ ASMAtomicWriteBool(&pCur->fTerminate, true);
+
+ /* try cancel local ipc operations that might be pending */
+ RTLocalIpcServerCancel(pThis->hServer);
+ for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ {
+ RTLOCALIPCSESSION hSession;
+ ASMAtomicReadHandle(&pCur->hSession, &hSession);
+ if (hSession != NIL_RTLOCALIPCSESSION)
+ RTLocalIpcSessionCancel(hSession);
+ }
+
+ /*
+ * Wait for the thread to respond (outside the crit sect).
+ */
+ RTCritSectLeave(&pThis->CritSect);
+ supSvcGrantWait(pThis, kSupSvcGrantState_Pausing, kSupSvcGrantState_Paused);
+ RTCritSectEnter(&pThis->CritSect);
+
+ /*
+ * Wait for any lingering sessions to exit.
+ */
+ supSvcGrantCleanUpSessionsLocked(pThis);
+ if (pThis->pSessionHead)
+ {
+ uint64_t u64StartTS = RTTimeMilliTS();
+ do
+ {
+ /* Destroy the sessions since cancelling didn't do the trick. */
+ for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ {
+ RTLOCALIPCSESSION hSession;
+ ASMAtomicXchgHandle(&pCur->hSession, NIL_RTLOCALIPCSESSION, &hSession);
+ if (hSession != NIL_RTLOCALIPCSESSION)
+ {
+ rc = RTLocalIpcSessionClose(hSession);
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ supSvcLogError("supSvcGrantStopAndDestroy: RTLocalIpcSessionClose(%p) returns %Rrc",
+ (uintptr_t)hSession, rc);
+ }
+ }
+
+ /* Check the time. */
+ uint64_t u64Elapsed = RTTimeMilliTS() - u64StartTS;
+ if (u64Elapsed >= 60*1000) /* 1 min */
+ break;
+
+ /* wait */
+ RTCritSectLeave(&pThis->CritSect);
+ rc = RTSemEventWait(pThis->hSessionEvent, 60*1000 - u64Elapsed);
+ RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc) && rc != VERR_TIMEOUT)
+ break;
+
+ /* cleanup and check again */
+ supSvcGrantCleanUpSessionsLocked(pThis);
+ } while (pThis->pSessionHead);
+ }
+ }
+
+ /*
+ * Tell the service thread to terminate and wait for it to do so.
+ */
+ pThis->enmState = kSupSvcGrantState_Terminating;
+ RTLOCALIPCSERVER hServer;
+ ASMAtomicXchgHandle(&pThis->hServer, NIL_RTLOCALIPCSERVER, &hServer);
+ RTThreadUserSignal(pThis->hThread);
+
+ RTCritSectLeave(&pThis->CritSect);
+
+ rc = RTThreadWait(pThis->hThread, 20*1000, NULL);
+ if (RT_FAILURE(rc) && rc == VERR_TIMEOUT)
+ {
+ RTThreadUserSignal(pThis->hThread);
+ RTLocalIpcServerDestroy(hServer);
+ hServer = NIL_RTLOCALIPCSERVER;
+
+ rc = RTThreadWait(pThis->hThread, 40*1000, NULL);
+ if (RT_FAILURE(rc))
+ supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(40 sec) returns %Rrc", rc);
+ }
+ else if (RT_FAILURE(rc))
+ supSvcLogError("supSvcGrantStopAndDestroy - RTThreadWait(20 sec) returns %Rrc", rc);
+ pThis->hThread = NIL_RTTHREAD;
+
+ /*
+ * Kill the parent pointers of any lingering sessions.
+ */
+ RTCritSectEnter(&pThis->CritSect);
+ pThis->enmState = kSupSvcGrantState_Destroyed;
+
+ supSvcGrantCleanUpSessionsLocked(pThis);
+ unsigned cSessions = 0;
+ for (PSUPSVCGRANTSESSION pCur = pThis->pSessionHead; pCur; pCur = pCur->pNext)
+ ASMAtomicWritePtr((void * volatile *)&pCur->pParent, NULL);
+
+ RTCritSectLeave(&pThis->CritSect);
+ if (cSessions)
+ supSvcLogError("supSvcGrantStopAndDestroy: %d session failed to terminate!", cSessions);
+
+ /*
+ * Free the resource.
+ */
+ RTLocalIpcServerDestroy(hServer);
+
+ RTSemEventDestroy(pThis->hResponseEvent);
+ pThis->hResponseEvent = NIL_RTSEMEVENT;
+
+ RTSemEventDestroy(pThis->hSessionEvent);
+ pThis->hSessionEvent = NIL_RTSEMEVENT;
+
+ RTCritSectDelete(&pThis->VerifyCritSect);
+ RTCritSectDelete(&pThis->CritSect);
+
+ RTMemFree(pThis);
+
+ Log(("supSvcGrantStopAndDestroy: done (rc=%Rrc)\n", rc));
+}
+
diff --git a/src/VBox/HostDrivers/Support/SUPSvcInternal.h b/src/VBox/HostDrivers/Support/SUPSvcInternal.h
new file mode 100644
index 000000000..05c244d11
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/SUPSvcInternal.h
@@ -0,0 +1,95 @@
+/* $Id: SUPSvcInternal.h 11725 2008-08-27 22:21:47Z vboxsync $ */
+/** @file
+ * VirtualBox Support Service - Internal header.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___SUPSvcInternal_h___
+#define ___SUPSvcInternal_h___
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <iprt/stdarg.h>
+#include <iprt/getopt.h>
+
+__BEGIN_DECLS
+
+/** @name Common Helpers
+ * @{ */
+void supSvcLogErrorStr(const char *pszMsg);
+void supSvcLogErrorV(const char *pszFormat, va_list va);
+void supSvcLogError(const char *pszFormat, ...);
+int supSvcLogGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue);
+int supSvcLogTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg);
+void supSvcDisplayErrorV(const char *pszFormat, va_list va);
+void supSvcDisplayError(const char *pszFormat, ...);
+int supSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue);
+int supSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg);
+/** @} */
+
+
+/** @name OS Backend
+ * @{ */
+/**
+ * Logs the message to the appropirate system log.
+ *
+ * @param psMsg The log string.
+ */
+void supSvcOsLogErrorStr(const char *pszMsg);
+/** @} */
+
+
+/** @name The Service Manager
+ * @{ */
+void supSvcStopAndDestroyServices(void);
+int supSvcTryStopServices(void);
+int supSvcCreateAndStartServices(void);
+/** @} */
+
+
+/** @name The Grant Service
+ * @{ */
+#define SUPSVC_GRANT_SERVICE_NAME "VirtualBoxGrantSvc"
+DECLCALLBACK(int) supSvcGrantCreate(void **ppvInstance);
+DECLCALLBACK(void) supSvcGrantStart(void *pvInstance);
+DECLCALLBACK(int) supSvcGrantTryStop(void *pvInstance);
+DECLCALLBACK(void) supSvcGrantStopAndDestroy(void *pvInstance, bool fRunning);
+/** @} */
+
+
+/** @name The Global Service
+ * @{ */
+DECLCALLBACK(int) supSvcGlobalCreate(void **ppvInstance);
+DECLCALLBACK(void) supSvcGlobalStart(void *pvInstance);
+DECLCALLBACK(int) supSvcGlobalTryStop(void *pvInstance);
+DECLCALLBACK(void) supSvcGlobalStopAndDestroy(void *pvInstance, bool fRunning);
+/** @} */
+
+__END_DECLS
+
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/darwin/Info-Tiger.plist b/src/VBox/HostDrivers/Support/darwin/Info-Tiger.plist
new file mode 100644
index 000000000..c3ba34d1e
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/Info-Tiger.plist
@@ -0,0 +1,39 @@
+
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleExecutable</key> <string>VBoxDrvTiger</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxDrv</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>VBoxDrvTiger</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>CFBundleGetInfoString</key> <string>VirtualBox @VBOX_VERSION_STRING@, © 2007 Sun Microsystems, Inc.</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>OSBundleCompatibleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ <key>VBoxDrv</key>
+ <dict>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxDrv</string>
+ <key>IOClass</key> <string>org_virtualbox_SupDrv</string>
+ <key>IOMatchCategory</key> <string>org_virtualbox_SupDrv</string>
+ <key>IOProviderClass</key> <string>IOResources</string>
+ <key>IOResourceMatch</key> <string>IOKit</string>
+ <key>IOUserClientClass</key> <string>org_virtualbox_SupDrvClient</string>
+ </dict>
+ </dict>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.bsd</key> <string>8.8.1</string>
+ <key>com.apple.kpi.mach</key> <string>8.8.1</string>
+ <key>com.apple.kpi.libkern</key> <string>8.8.1</string>
+ <key>com.apple.kpi.unsupported</key> <string>8.8.1</string>
+ <key>com.apple.kpi.iokit</key> <string>8.8.1</string>
+ <key>com.apple.kernel.bsd</key> <string>7.9.9</string>
+ <key>com.apple.kernel.mach</key> <string>7.9.9</string>
+ </dict>
+</dict>
+</plist>
diff --git a/src/VBox/HostDrivers/Support/darwin/Info.plist b/src/VBox/HostDrivers/Support/darwin/Info.plist
new file mode 100644
index 000000000..a577d5866
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/Info.plist
@@ -0,0 +1,39 @@
+
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleExecutable</key> <string>VBoxDrv</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxDrv</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>VBoxDrv</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>CFBundleGetInfoString</key> <string>VirtualBox @VBOX_VERSION_STRING@, © 2007 Sun Microsystems, Inc.</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>OSBundleCompatibleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ <key>VBoxDrv</key>
+ <dict>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxDrv</string>
+ <key>IOClass</key> <string>org_virtualbox_SupDrv</string>
+ <key>IOMatchCategory</key> <string>org_virtualbox_SupDrv</string>
+ <key>IOProviderClass</key> <string>IOResources</string>
+ <key>IOResourceMatch</key> <string>IOKit</string>
+ <key>IOUserClientClass</key> <string>org_virtualbox_SupDrvClient</string>
+ </dict>
+ </dict>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.bsd</key> <string>8.8.1</string>
+ <key>com.apple.kpi.mach</key> <string>8.8.1</string>
+ <key>com.apple.kpi.libkern</key> <string>8.8.1</string>
+ <key>com.apple.kpi.unsupported</key> <string>8.8.1</string>
+ <key>com.apple.kpi.iokit</key> <string>8.8.1</string>
+ <key>com.apple.kernel.bsd</key> <string>7.9.9</string>
+ <key>com.apple.kernel.mach</key> <string>7.9.9</string>
+ </dict>
+</dict>
+</plist>
diff --git a/src/VBox/HostDrivers/Support/darwin/Makefile.kup b/src/VBox/HostDrivers/Support/darwin/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp b/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp
new file mode 100644
index 000000000..c47ba6863
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp
@@ -0,0 +1,1126 @@
+/* $Id: $ */
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Darwin host:
+ * Darwin driver C code
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+/*
+ * Deal with conflicts first.
+ * PVM - BSD mess, that FreeBSD has correct a long time ago.
+ * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
+ */
+#include <iprt/types.h>
+#include <sys/param.h>
+#undef PVM
+
+#include <IOKit/IOLib.h> /* Assert as function */
+
+#include "../SUPDrvInternal.h"
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+#include <iprt/alloc.h>
+#include <iprt/power.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <mach/kmod.h>
+#include <miscfs/devfs/devfs.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOUserclient.h>
+#include <IOKit/pwr_mgt/RootDomain.h>
+
+#ifdef VBOX_WITH_HOST_VMX
+__BEGIN_DECLS
+# include <i386/vmx.h>
+__END_DECLS
+#endif
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+
+/** The module name. */
+#define DEVICE_NAME "vboxdrv"
+
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+__BEGIN_DECLS
+static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
+static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
+
+static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
+static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
+
+static int VBoxDrvDarwinErr2DarwinErr(int rc);
+
+static IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
+__END_DECLS
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The service class.
+ * This is just a formality really.
+ */
+class org_virtualbox_SupDrv : public IOService
+{
+ OSDeclareDefaultStructors(org_virtualbox_SupDrv);
+
+public:
+ virtual bool init(OSDictionary *pDictionary = 0);
+ virtual void free(void);
+ virtual bool start(IOService *pProvider);
+ virtual void stop(IOService *pProvider);
+ virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
+ virtual bool terminate(IOOptionBits fOptions);
+};
+
+OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
+
+
+/**
+ * An attempt at getting that clientDied() notification.
+ * I don't think it'll work as I cannot figure out where/what creates the correct
+ * port right.
+ */
+class org_virtualbox_SupDrvClient : public IOUserClient
+{
+ OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
+
+private:
+ PSUPDRVSESSION m_pSession; /**< The session. */
+ task_t m_Task; /**< The client task. */
+ org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
+
+public:
+ virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
+ virtual bool start(IOService *pProvider);
+ static void sessionClose(RTPROCESS Process);
+ virtual IOReturn clientClose(void);
+ virtual IOReturn clientDied(void);
+ virtual bool terminate(IOOptionBits fOptions = 0);
+ virtual bool finalize(IOOptionBits fOptions);
+ virtual void stop(IOService *pProvider);
+};
+
+OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
+
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Declare the module stuff.
+ */
+__BEGIN_DECLS
+extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
+extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
+
+KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
+DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
+DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
+DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
+__END_DECLS
+
+
+/**
+ * Device extention & session data association structure.
+ */
+static SUPDRVDEVEXT g_DevExt;
+
+/**
+ * The character device switch table for the driver.
+ */
+static struct cdevsw g_DevCW =
+{
+ /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
+ /*.d_open = */VBoxDrvDarwinOpen,
+ /*.d_close = */VBoxDrvDarwinClose,
+ /*.d_read = */eno_rdwrt,
+ /*.d_write = */eno_rdwrt,
+ /*.d_ioctl = */VBoxDrvDarwinIOCtl,
+ /*.d_stop = */eno_stop,
+ /*.d_reset = */eno_reset,
+ /*.d_ttys = */NULL,
+ /*.d_select= */eno_select,
+ /*.d_mmap = */eno_mmap,
+ /*.d_strategy = */eno_strat,
+ /*.d_getc = */eno_getc,
+ /*.d_putc = */eno_putc,
+ /*.d_type = */0
+};
+
+/** Major device number. */
+static int g_iMajorDeviceNo = -1;
+/** Registered devfs device handle. */
+static void *g_hDevFsDevice = NULL;
+
+/** Spinlock protecting g_apSessionHashTab. */
+static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
+/** Hash table */
+static PSUPDRVSESSION g_apSessionHashTab[19];
+/** Calculates the index into g_apSessionHashTab.*/
+#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
+/** The number of open sessions. */
+static int32_t volatile g_cSessions = 0;
+/** The notifier handle for the sleep callback handler. */
+static IONotifier *g_pSleepNotifier = NULL;
+
+
+
+/**
+ * Start the kernel module.
+ */
+static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
+{
+ int rc;
+#ifdef DEBUG
+ printf("VBoxDrvDarwinStart\n");
+#endif
+
+ /*
+ * Initialize IPRT.
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the device extension.
+ */
+ rc = supdrvInitDevExt(&g_DevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the session hash table.
+ */
+ memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
+ rc = RTSpinlockCreate(&g_Spinlock);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Registering ourselves as a character device.
+ */
+ g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
+ if (g_iMajorDeviceNo >= 0)
+ {
+#ifdef VBOX_WITH_HARDENING
+ g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
+ UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME);
+#else
+ g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
+ UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME);
+#endif
+ if (g_hDevFsDevice)
+ {
+ LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
+ VBOX_SVN_REV, SUPDRV_IOC_VERSION, SUPDRV_IDC_VERSION, g_iMajorDeviceNo));
+
+ /* Register a sleep/wakeup notification callback */
+ g_pSleepNotifier = registerPrioritySleepWakeInterest(&VBoxDrvDarwinSleepHandler, &g_DevExt, NULL);
+ if (g_pSleepNotifier == NULL)
+ LogRel(("VBoxDrv: register for sleep/wakeup events failed\n"));
+
+ return KMOD_RETURN_SUCCESS;
+ }
+
+ LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME));
+ cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
+ g_iMajorDeviceNo = -1;
+ }
+ else
+ LogRel(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
+ RTSpinlockDestroy(g_Spinlock);
+ g_Spinlock = NIL_RTSPINLOCK;
+ }
+ else
+ LogRel(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
+ supdrvDeleteDevExt(&g_DevExt);
+ }
+ else
+ printf("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc);
+ RTR0Term();
+ }
+ else
+ printf("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc);
+
+ memset(&g_DevExt, 0, sizeof(g_DevExt));
+ return KMOD_RETURN_FAILURE;
+}
+
+
+/**
+ * Stop the kernel module.
+ */
+static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
+{
+ int rc;
+ LogFlow(("VBoxDrvDarwinStop\n"));
+
+ /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
+ * unloading if we're busy. Investigate and implement this! */
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ if (g_pSleepNotifier)
+ {
+ g_pSleepNotifier->remove();
+ g_pSleepNotifier = NULL;
+ }
+
+ devfs_remove(g_hDevFsDevice);
+ g_hDevFsDevice = NULL;
+
+ rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
+ Assert(rc == g_iMajorDeviceNo);
+ g_iMajorDeviceNo = -1;
+
+ supdrvDeleteDevExt(&g_DevExt);
+
+ rc = RTSpinlockDestroy(g_Spinlock);
+ AssertRC(rc);
+ g_Spinlock = NIL_RTSPINLOCK;
+
+ RTR0Term();
+
+ memset(&g_DevExt, 0, sizeof(g_DevExt));
+#ifdef DEBUG
+ printf("VBoxDrvDarwinStop - done\n");
+#endif
+ return KMOD_RETURN_SUCCESS;
+}
+
+
+/**
+ * Device open. Called on open /dev/vboxdrv
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+#ifdef DEBUG_DARWIN_GIP
+ char szName[128];
+ szName[0] = '\0';
+ proc_name(proc_pid(pProcess), szName, sizeof(szName));
+ Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
+#endif
+
+ /*
+ * Find the session created by org_virtualbox_SupDrvClient, fail
+ * if no such session, and mark it as opened. We set the uid & gid
+ * here too, since that is more straight forward at this point.
+ */
+ int rc = VINF_SUCCESS;
+ PSUPDRVSESSION pSession = NULL;
+ struct ucred *pCred = proc_ucred(pProcess);
+ if (pCred)
+ {
+ RTUID Uid = pCred->cr_ruid;
+ RTGID Gid = pCred->cr_rgid;
+ RTPROCESS Process = RTProcSelf();
+ unsigned iHash = SESSION_HASH(Process);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession && pSession->Process != Process)
+ {
+ do pSession = pSession->pNextHash;
+ while (pSession && pSession->Process != Process);
+ }
+ if (pSession)
+ {
+ if (!pSession->fOpened)
+ {
+ pSession->fOpened = true;
+ pSession->Uid = Uid;
+ pSession->Gid = Gid;
+ }
+ else
+ rc = VERR_ALREADY_LOADED;
+ }
+ else
+ rc = VERR_GENERAL_FAILURE;
+
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ }
+ else
+ rc = SUPDRV_ERR_INVALID_PARAM;
+
+#ifdef DEBUG_DARWIN_GIP
+ OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
+#else
+ Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
+#endif
+ return VBoxDrvDarwinErr2DarwinErr(rc);
+}
+
+
+/**
+ * Close device.
+ */
+static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+ Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
+ Assert(proc_pid(pProcess) == (int)RTProcSelf());
+
+ /*
+ * Hand the session closing to org_virtualbox_SupDrvClient.
+ */
+ org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
+ return 0;
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
+ * @param Dev The device number (major+minor).
+ * @param iCmd The IOCtl command.
+ * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
+ * @param fFlags Flag saying we're a character device (like we didn't know already).
+ * @param pProcess The process issuing this request.
+ */
+static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ const RTPROCESS Process = proc_pid(pProcess);
+ const unsigned iHash = SESSION_HASH(Process);
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Find the session.
+ */
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession && pSession->Process != Process)
+ {
+ do pSession = pSession->pNextHash;
+ while (pSession && pSession->Process != Process);
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
+ (int)Process, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Deal with the two high-speed IOCtl that takes it's arguments from
+ * the session and iCmd, and only returns a VBox status code.
+ */
+ if ( iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || iCmd == SUP_IOCTL_FAST_DO_NOP)
+ return supdrvIOCtlFast(iCmd, *(uint32_t *)pData, &g_DevExt, pSession);
+ return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
+}
+
+
+/**
+ * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
+ *
+ * @returns Darwin errno.
+ *
+ * @param pSession The session.
+ * @param iCmd The IOCtl command.
+ * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
+ * @param pProcess The calling process.
+ */
+static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
+{
+ LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
+
+
+ /*
+ * Buffered or unbuffered?
+ */
+ PSUPREQHDR pHdr;
+ user_addr_t pUser = 0;
+ void *pvPageBuf = NULL;
+ uint32_t cbReq = IOCPARM_LEN(iCmd);
+ if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
+ {
+ pHdr = (PSUPREQHDR)pData;
+ if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
+ return EINVAL;
+ }
+ if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
+ return EINVAL;
+ }
+ if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
+ || pHdr->cbIn < sizeof(*pHdr)
+ || pHdr->cbOut < sizeof(*pHdr)))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
+ return EINVAL;
+ }
+ }
+ else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
+ {
+ /*
+ * Get the header and figure out how much we're gonna have to read.
+ */
+ SUPREQHDR Hdr;
+ pUser = (user_addr_t)*(void **)pData;
+ int rc = copyin(pUser, &Hdr, sizeof(Hdr));
+ if (RT_UNLIKELY(rc))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
+ return rc;
+ }
+ if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
+ return EINVAL;
+ }
+ cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
+ if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
+ || Hdr.cbOut < sizeof(Hdr)
+ || cbReq > _1M*16))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Allocate buffer and copy in the data.
+ */
+ pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
+ if (!pHdr)
+ pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
+ if (RT_UNLIKELY(!pHdr))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
+ return ENOMEM;
+ }
+ rc = copyin(pUser, pHdr, Hdr.cbIn);
+ if (RT_UNLIKELY(rc))
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
+ (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pHdr);
+ return rc;
+ }
+ }
+ else
+ {
+ Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
+ if (RT_LIKELY(!rc))
+ {
+ /*
+ * If not buffered, copy back the buffer before returning.
+ */
+ if (pUser)
+ {
+ uint32_t cbOut = pHdr->cbOut;
+ if (cbOut > cbReq)
+ {
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
+ cbOut = cbReq;
+ }
+ rc = copyout(pHdr, pUser, cbOut);
+ if (RT_UNLIKELY(rc))
+ OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
+ pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
+
+ /* cleanup */
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pHdr);
+ }
+ }
+ else
+ {
+ /*
+ * The request failed, just clean up.
+ */
+ if (pUser)
+ {
+ if (pvPageBuf)
+ IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ else
+ RTMemTmpFree(pHdr);
+ }
+
+ Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
+ rc = EINVAL;
+ }
+
+ Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code, see supdrvIDC.
+ * @param iReq The request code.
+ * @param pReq The request.
+ */
+int VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Some quick validations.
+ */
+ if (RT_UNLIKELY(!VALID_PTR(pReq)))
+ return VERR_INVALID_POINTER;
+
+ pSession = pReq->pSession;
+ if (pSession)
+ {
+ if (RT_UNLIKELY(!VALID_PTR(pSession)))
+ return VERR_INVALID_PARAMETER;
+ if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
+ return VERR_INVALID_PARAMETER;
+ }
+ else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Do the job.
+ */
+ return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
+}
+
+
+/**
+ * Initializes any OS specific object creator fields.
+ */
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+/**
+ * Checks if the session can access the object.
+ *
+ * @returns true if a decision has been made.
+ * @returns false if the default access policy should be applied.
+ *
+ * @param pObj The object in question.
+ * @param pSession The session wanting to access the object.
+ * @param pszObjName The object name, can be NULL.
+ * @param prc Where to store the result when returning true.
+ */
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+/**
+ * Callback for blah blah blah.
+ */
+IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType, IOService * /* pProvider */, void * /* pvMessageArgument */, vm_size_t /* argSize */)
+{
+ LogFlow(("VBoxDrv: Got sleep/wake notice. Message type was %X\n", (uint)uMessageType));
+
+ if (uMessageType == kIOMessageSystemWillSleep)
+ RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
+ else if (uMessageType == kIOMessageSystemHasPoweredOn)
+ RTPowerSignalEvent(RTPOWEREVENT_RESUME);
+
+ acknowledgeSleepWakeNotification(pvRefCon);
+
+ return 0;
+}
+
+
+/**
+ * Enables or disables VT-x using kernel functions.
+ *
+ * @returns VBox status code. VERR_NOT_SUPPORTED has a special meaning.
+ * @param fEnable Whether to enable or disable.
+ */
+int VBOXCALL supdrvOSEnableVTx(bool fEnable)
+{
+/* Zarking amateurish Apple engineering!
+ host_vmxon is actually buggy and may panic multicore machines. Reason, it
+ uses a simple lock which will disable preemption of the cpu/thread trying
+ to acquire it. Then it allocate wired memory in the kernel map for each
+ of the cpus in the system. If anyone else tries to mess around in the
+ kernel map on another CPU while this is going on, there is a fair chance
+ that it might cause the host_vmxon thread to block and hence panic since
+ preemption is disabled. Arrrg! */
+#if 0 /*def VBOX_WITH_HOST_VMX*/
+ int rc;
+ if (fEnable)
+ {
+ rc = host_vmxon(false /* exclusive */);
+ if (rc == 0 /* all ok */)
+ rc = VINF_SUCCESS;
+ else if (rc == 1 /* unsupported */)
+ rc = VERR_VMX_NO_VMX;
+ else if (rc == 2 /* exclusive user */)
+ rc = VERR_VMX_IN_VMX_ROOT_MODE;
+ else /* shouldn't happen, but just in case. */
+ {
+ LogRel(("host_vmxon returned %d\n", rc));
+ rc = VERR_UNRESOLVED_ERROR;
+ }
+ }
+ else
+ {
+ host_vmxoff();
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ NOREF(pDevExt);
+ return false;
+}
+
+
+/**
+ * Converts a supdrv error code to a darwin error code.
+ *
+ * @returns corresponding darwin error code.
+ * @param rc supdrv error code (SUPDRV_ERR_* defines).
+ */
+static int VBoxDrvDarwinErr2DarwinErr(int rc)
+{
+ switch (rc)
+ {
+ case 0: return 0;
+ case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
+ case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
+ case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
+ case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
+ case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
+ case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
+ case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
+ case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
+ case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
+ }
+
+ return EPERM;
+}
+
+
+/** @todo move this to assembly where a simple "jmp printf" will to the trick. */
+RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+ va_list args;
+ char szMsg[512];
+
+ va_start(args, pszFormat);
+ vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
+ va_end(args);
+
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ printf("%s", szMsg);
+ return 0;
+}
+
+
+/*
+ *
+ * org_virtualbox_SupDrv
+ *
+ */
+
+
+/**
+ * Initialize the object.
+ */
+bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
+{
+ LogFlow(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
+ if (IOService::init(pDictionary))
+ {
+ /* init members. */
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Free the object.
+ */
+void org_virtualbox_SupDrv::free(void)
+{
+ LogFlow(("IOService::free([%p])\n", this));
+ IOService::free();
+}
+
+
+/**
+ * Check if it's ok to start this service.
+ * It's always ok by us, so it's up to IOService to decide really.
+ */
+IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
+{
+ LogFlow(("org_virtualbox_SupDrv::probe([%p])\n", this));
+ return IOService::probe(pProvider, pi32Score);
+}
+
+
+/**
+ * Start this service.
+ */
+bool org_virtualbox_SupDrv::start(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
+
+ if (IOService::start(pProvider))
+ {
+ /* register the service. */
+ registerService();
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Stop this service.
+ */
+void org_virtualbox_SupDrv::stop(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
+ IOService::stop(pProvider);
+}
+
+
+/**
+ * Termination request.
+ *
+ * @return true if we're ok with shutting down now, false if we're not.
+ * @param fOptions Flags.
+ */
+bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
+{
+ bool fRc;
+ LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
+ KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
+ if ( KMOD_INFO_NAME.reference_count != 0
+ || ASMAtomicUoReadS32(&g_cSessions))
+ fRc = false;
+ else
+ fRc = IOService::terminate(fOptions);
+ LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
+ return fRc;
+}
+
+
+/*
+ *
+ * org_virtualbox_SupDrvClient
+ *
+ */
+
+
+/**
+ * Initializer called when the client opens the service.
+ */
+bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
+ this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
+ AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
+
+ if (!OwningTask)
+ return false;
+ if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
+ {
+ m_Task = OwningTask;
+ m_pSession = NULL;
+ m_pProvider = NULL;
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Start the client service.
+ */
+bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
+ this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
+ AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
+ ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
+ false);
+
+ if (IOUserClient::start(pProvider))
+ {
+ m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
+ if (m_pProvider)
+ {
+ Assert(!m_pSession);
+
+ /*
+ * Create a new session.
+ */
+ int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &m_pSession);
+ if (RT_SUCCESS(rc))
+ {
+ m_pSession->fOpened = false;
+ /* The Uid and Gid fields are set on open. */
+
+ /*
+ * Insert it into the hash table, checking that there isn't
+ * already one for this process first.
+ */
+ unsigned iHash = SESSION_HASH(m_pSession->Process);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+
+ PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
+ if (pCur && pCur->Process != m_pSession->Process)
+ {
+ do pCur = pCur->pNextHash;
+ while (pCur && pCur->Process != m_pSession->Process);
+ }
+ if (!pCur)
+ {
+ m_pSession->pNextHash = g_apSessionHashTab[iHash];
+ g_apSessionHashTab[iHash] = m_pSession;
+ m_pSession->pvSupDrvClient = this;
+ ASMAtomicIncS32(&g_cSessions);
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_ALREADY_LOADED;
+
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
+ return true;
+ }
+
+ LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
+ supdrvCloseSession(&g_DevExt, m_pSession);
+ }
+
+ m_pSession = NULL;
+ LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
+ }
+ else
+ LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
+ }
+ return false;
+}
+
+
+/**
+ * Common worker for clientClose and VBoxDrvDarwinClose.
+ *
+ * It will
+ */
+/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
+{
+ /*
+ * Look for the session.
+ */
+ const unsigned iHash = SESSION_HASH(Process);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ PSUPDRVSESSION pSession = g_apSessionHashTab[iHash];
+ if (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ g_apSessionHashTab[iHash] = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ ASMAtomicDecS32(&g_cSessions);
+ }
+ else
+ {
+ PSUPDRVSESSION pPrev = pSession;
+ pSession = pSession->pNextHash;
+ while (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ pPrev->pNextHash = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ ASMAtomicDecS32(&g_cSessions);
+ break;
+ }
+
+ /* next */
+ pPrev = pSession;
+ pSession = pSession->pNextHash;
+ }
+ }
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
+ return;
+ }
+
+ /*
+ * Remove it from the client object.
+ */
+ org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
+ pSession->pvSupDrvClient = NULL;
+ if (pThis)
+ {
+ Assert(pThis->m_pSession == pSession);
+ pThis->m_pSession = NULL;
+ }
+
+ /*
+ * Close the session.
+ */
+ supdrvCloseSession(&g_DevExt, pSession);
+}
+
+
+/**
+ * Client exits normally.
+ */
+IOReturn org_virtualbox_SupDrvClient::clientClose(void)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
+ AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
+
+ /*
+ * Clean up the session if it's still around.
+ *
+ * We cannot rely 100% on close, and in the case of a dead client
+ * we'll end up hanging inside vm_map_remove() if we postpone it.
+ */
+ if (m_pSession)
+ {
+ sessionClose(RTProcSelf());
+ Assert(!m_pSession);
+ }
+
+ m_pProvider = NULL;
+ terminate();
+
+ return kIOReturnSuccess;
+}
+
+
+/**
+ * The client exits abnormally / forgets to do cleanups. (logging)
+ */
+IOReturn org_virtualbox_SupDrvClient::clientDied(void)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n",
+ this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
+
+ /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
+ return IOUserClient::clientDied();
+}
+
+
+/**
+ * Terminate the service (initiate the destruction). (logging)
+ */
+bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::terminate([%p], %#x)\n", this, fOptions));
+ return IOUserClient::terminate(fOptions);
+}
+
+
+/**
+ * The final stage of the client service destruction. (logging)
+ */
+bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::finalize([%p], %#x)\n", this, fOptions));
+ return IOUserClient::finalize(fOptions);
+}
+
+
+/**
+ * Stop the client service. (logging)
+ */
+void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
+{
+ LogFlow(("org_virtualbox_SupDrvClient::stop([%p])\n", this));
+ IOUserClient::stop(pProvider);
+}
+
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
new file mode 100644
index 000000000..215fc3129
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
@@ -0,0 +1,304 @@
+/* $Id: $ */
+/** @file
+ * VirtualBox Support Library - Darwin specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <VBox/types.h>
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <mach/mach_port.h>
+#include <IOKit/IOKitLib.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** BSD Device name. */
+#define DEVICE_NAME "/dev/vboxdrv"
+/** The IOClass key of the service (see SUPDrv-darwin.cpp / Info.plist). */
+#define IOCLASS_NAME "org_virtualbox_SupDrv"
+
+
+
+/**
+ * Opens the BSD device node.
+ *
+ * @returns VBox status code.
+ */
+static int suplibDarwinOpenDevice(PSUPLIBDATA pThis)
+{
+ /*
+ * Open the BSD device.
+ * This will connect to the session created when the SupDrvClient was
+ * started, so it has to be done after opening the service (IOC v9.1+).
+ */
+ int hDevice = open(DEVICE_NAME, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ int rc;
+ switch (errno)
+ {
+ case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
+ case EPERM:
+ case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
+ case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ LogRel(("SUP: Failed to open \"%s\", errno=%d, rc=%Rrc\n", DEVICE_NAME, errno, rc));
+ return rc;
+ }
+
+ /*
+ * Mark the file handle close on exec.
+ */
+ if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) != 0)
+ {
+#ifdef IN_SUP_HARDENED_R3
+ int rc = VERR_INTERNAL_ERROR;
+#else
+ int err = errno;
+ int rc = RTErrConvertFromErrno(err);
+ LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d (%Rrc)\n", err, rc));
+#endif
+ close(hDevice);
+ return rc;
+ }
+
+ pThis->hDevice = hDevice;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Opens the IOKit service, instantiating org_virtualbox_SupDrvClient.
+ *
+ * @returns VBox status code.
+ */
+static int suplibDarwinOpenService(PSUPLIBDATA pThis)
+{
+ /*
+ * Open the IOKit client first - The first step is finding the service.
+ */
+ mach_port_t MasterPort;
+ kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
+ if (kr != kIOReturnSuccess)
+ {
+ LogRel(("IOMasterPort -> %d\n", kr));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ CFDictionaryRef ClassToMatch = IOServiceMatching(IOCLASS_NAME);
+ if (!ClassToMatch)
+ {
+ LogRel(("IOServiceMatching(\"%s\") failed.\n", IOCLASS_NAME));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /* Create an io_iterator_t for all instances of our drivers class that exist in the IORegistry. */
+ io_iterator_t Iterator;
+ kr = IOServiceGetMatchingServices(MasterPort, ClassToMatch, &Iterator);
+ if (kr != kIOReturnSuccess)
+ {
+ LogRel(("IOServiceGetMatchingServices returned %d\n", kr));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ /* Get the first item in the iterator and release it. */
+ io_service_t ServiceObject = IOIteratorNext(Iterator);
+ IOObjectRelease(Iterator);
+ if (!ServiceObject)
+ {
+ LogRel(("SUP: Couldn't find any matches. The kernel module is probably not loaded.\n"));
+ return VERR_VM_DRIVER_NOT_INSTALLED;
+ }
+
+ /*
+ * Open the service.
+ *
+ * This will cause the user client class in SUPDrv-darwin.cpp to be
+ * instantiated and create a session for this process.
+ */
+ io_connect_t Connection = NULL;
+ kr = IOServiceOpen(ServiceObject, mach_task_self(), 0, &Connection);
+ IOObjectRelease(ServiceObject);
+ if (kr != kIOReturnSuccess)
+ {
+ LogRel(("SUP: IOServiceOpen returned %d. Driver open failed.\n", kr));
+ pThis->pvConnection = NULL;
+ return VERR_VM_DRIVER_OPEN_ERROR;
+ }
+
+ AssertCompile(sizeof(void *) == sizeof(Connection));
+ pThis->pvConnection = (void *)Connection;
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+
+ /*
+ * Do the job.
+ */
+ Assert(pThis->hDevice == NIL_RTFILE);
+ int rc = suplibDarwinOpenService(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ rc = suplibDarwinOpenDevice(pThis);
+ if (RT_FAILURE(rc))
+ {
+ kern_return_t kr = IOServiceClose((io_connect_t)pThis->pvConnection);
+ if (kr != kIOReturnSuccess)
+ {
+ LogRel(("Warning: IOServiceClose(%p) returned %d\n", pThis->pvConnection, kr));
+ AssertFailed();
+ }
+ pThis->pvConnection = NULL;
+ }
+ }
+
+ return rc;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Close the connection to the IOService.
+ * This will cause the SUPDRVSESSION to be closed (starting IOC 9.1).
+ */
+ if (pThis->pvConnection)
+ {
+ kern_return_t kr = IOServiceClose((io_connect_t)pThis->pvConnection);
+ if (kr != kIOReturnSuccess)
+ {
+ LogRel(("Warning: IOServiceClose(%p) returned %d\n", pThis->pvConnection, kr));
+ AssertFailed();
+ }
+ pThis->pvConnection = NULL;
+ }
+
+ /*
+ * Check if we're initited at all.
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ if (close(pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = NIL_RTFILE;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsInstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsUninstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
+ return VINF_SUCCESS;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ int rc = ioctl(pThis->hDevice, uFunction, NULL);
+ if (rc == -1)
+ rc = errno;
+ return rc;
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ NOREF(pThis);
+ *ppvPages = valloc(cPages << PAGE_SHIFT);
+ if (*ppvPages)
+ {
+ memset(*ppvPages, 0, cPages << PAGE_SHIFT);
+ return VINF_SUCCESS;
+ }
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
+{
+ NOREF(pThis);
+ free(pvPages);
+ return VINF_SUCCESS;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPR0IdcClient-darwin.c b/src/VBox/HostDrivers/Support/darwin/SUPR0IdcClient-darwin.c
new file mode 100644
index 000000000..1351f1cb2
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/darwin/SUPR0IdcClient-darwin.c
@@ -0,0 +1,59 @@
+/* $Id: SUPR0IdcClient-darwin.c 10262 2008-07-04 23:42:33Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Darwin Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc = SUPDrvDarwinIDC(iReq, pReq);
+ if (RT_SUCCESS(rc))
+ rc = pReq->rc;
+
+ NOREF(pHandle);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/freebsd/Makefile.kup b/src/VBox/HostDrivers/Support/freebsd/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/freebsd/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c b/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
new file mode 100644
index 000000000..8201b475b
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
@@ -0,0 +1,586 @@
+/* $Id: SUPDrv-freebsd.c 16030 2009-01-19 05:24:30Z vboxsync $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - FreeBSD specifics.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+/* Deal with conflicts first. */
+#include <sys/param.h>
+#undef PVM
+#include <sys/types.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+
+#include "../SUPDrvInternal.h"
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/spinlock.h>
+#include <iprt/process.h>
+#include <iprt/assert.h>
+#include <VBox/log.h>
+#include <iprt/alloc.h>
+#include <iprt/err.h>
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg);
+static int VBoxDrvFreeBSDLoad(void);
+static int VBoxDrvFreeBSDUnload(void);
+static void VBoxDrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pachName, int cchName, struct cdev **ppDev);
+
+static d_fdopen_t VBoxDrvFreeBSDOpen;
+static d_close_t VBoxDrvFreeBSDClose;
+static d_ioctl_t VBoxDrvFreeBSDIOCtl;
+static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd);
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Module info structure used by the kernel.
+ */
+static moduledata_t g_VBoxDrvFreeBSDModule =
+{
+ "vboxdrv",
+ VBoxDrvFreeBSDModuleEvent,
+ NULL
+};
+
+/** Declare the module as a pseudo device. */
+DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+/**
+ * The /dev/vboxdrv character device entry points.
+ */
+static struct cdevsw g_VBoxDrvFreeBSDChrDevSW =
+{
+ .d_version = D_VERSION,
+ .d_flags = D_PSEUDO | D_TRACKCLOSE,
+ .d_fdopen = VBoxDrvFreeBSDOpen,
+ .d_close = VBoxDrvFreeBSDClose,
+ .d_ioctl = VBoxDrvFreeBSDIOCtl,
+ .d_name = "vboxdrv"
+};
+
+/** List of cloned device. Managed by the kernel. */
+static struct clonedevs *g_pVBoxDrvFreeBSDClones;
+/** The dev_clone event handler tag. */
+static eventhandler_tag g_VBoxDrvFreeBSDEHTag;
+
+/** The device extention. */
+static SUPDRVDEVEXT g_VBoxDrvFreeBSDDevExt;
+
+
+
+
+/**
+ * Module event handler.
+ *
+ * @param pMod The module structure.
+ * @param enmEventType The event type (modeventtype_t).
+ * @param pvArg Module argument. NULL.
+ *
+ * @return 0 on success, errno.h status code on failure.
+ */
+static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
+{
+ int rc;
+ switch (enmEventType)
+ {
+ case MOD_LOAD:
+ rc = VBoxDrvFreeBSDLoad();
+ break;
+
+ case MOD_UNLOAD:
+ rc = VBoxDrvFreeBSDUnload();
+ break;
+
+ case MOD_SHUTDOWN:
+ case MOD_QUIESCE:
+ default:
+ return EOPNOTSUPP;
+ }
+
+ if (RT_SUCCESS(rc))
+ return 0;
+ return RTErrConvertToErrno(rc);
+}
+
+
+static int VBoxDrvFreeBSDLoad(void)
+{
+ dprintf(("VBoxDrvFreeBSDLoad:\n"));
+
+ /*
+ * Initialize the runtime.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the device extension.
+ */
+ rc = supdrvInitDevExt(&g_VBoxDrvFreeBSDDevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Configure device cloning.
+ */
+ clone_setup(&g_pVBoxDrvFreeBSDClones);
+ g_VBoxDrvFreeBSDEHTag = EVENTHANDLER_REGISTER(dev_clone, VBoxDrvFreeBSDClone, 0, 1000);
+ if (g_VBoxDrvFreeBSDEHTag)
+ {
+ dprintf(("VBoxDrvFreeBSDLoad: returns successfully\n"));
+ return VINF_SUCCESS;
+ }
+
+ printf("vboxdrv: EVENTHANDLER_REGISTER(dev_clone,,,) failed\n");
+ clone_cleanup(&g_pVBoxDrvFreeBSDClones);
+ rc = SUPDRV_ERR_ALREADY_LOADED;
+ supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt);
+ }
+ else
+ printf("vboxdrv: supdrvInitDevExt failed, rc=%d\n", rc);
+ RTR0Term();
+ }
+ else
+ printf("vboxdrv: RTR0Init failed, rc=%d\n", rc);
+ return rc;
+}
+
+static int VBoxDrvFreeBSDUnload(void)
+{
+ dprintf(("VBoxDrvFreeBSDUnload:\n"));
+
+ /** @todo verify that FreeBSD does reference counting. */
+
+ /*
+ * Reserve what we did in VBoxDrvFreeBSDInit.
+ */
+ clone_cleanup(&g_pVBoxDrvFreeBSDClones);
+
+ supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt);
+
+ RTR0Term();
+
+ memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt));
+
+ dprintf(("VBoxDrvFreeBSDUnload: returns\n"));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * DEVFS event handler.
+ */
+static void VBoxDrvFreeBSDClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev)
+{
+ int iUnit;
+ int rc;
+
+ dprintf(("VBoxDrvFreeBSDClone: pszName=%s ppDev=%p\n", pszName, ppDev));
+
+ /*
+ * One device node per user, si_drv1 points to the session.
+ * /dev/vboxdrv<N> where N = {0...255}.
+ */
+ if (!ppDev)
+ return;
+ if (dev_stdclone(pszName, NULL, "vboxdrv", &iUnit) != 1)
+ return;
+ if (iUnit >= 256 || iUnit < 0)
+ {
+ dprintf(("VBoxDrvFreeBSDClone: iUnit=%d >= 256 - rejected\n", iUnit));
+ return;
+ }
+
+ dprintf(("VBoxDrvFreeBSDClone: pszName=%s iUnit=%d\n", pszName, iUnit));
+
+ rc = clone_create(&g_pVBoxDrvFreeBSDClones, &g_VBoxDrvFreeBSDChrDevSW, &iUnit, ppDev, 0);
+ dprintf(("VBoxDrvFreeBSDClone: clone_create -> %d; iUnit=%d\n", rc, iUnit));
+ if (rc)
+ {
+#ifdef VBOX_WITH_HARDENING
+ *ppDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, unit2minor(iUnit), UID_ROOT, GID_WHEEL, 0600, "vboxdrv%d", iUnit);
+#else
+ *ppDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, unit2minor(iUnit), UID_ROOT, GID_WHEEL, 0666, "vboxdrv%d", iUnit);
+#endif
+ if (*ppDev)
+ {
+ dev_ref(*ppDev);
+ (*ppDev)->si_flags |= SI_CHEAPCLONE;
+ dprintf(("VBoxDrvFreeBSDClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
+ *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2));
+ (*ppDev)->si_drv1 = (*ppDev)->si_drv2 = NULL;
+ }
+ else
+ OSDBGPRINT(("VBoxDrvFreeBSDClone: make_dev iUnit=%d failed\n", iUnit));
+ }
+ else
+ dprintf(("VBoxDrvFreeBSDClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
+ *ppDev, iUnit, (*ppDev)->si_drv1, (*ppDev)->si_drv2));
+}
+
+
+
+/**
+ *
+ * @returns 0 on success, errno on failure.
+ * EBUSY if the device is used by someone else.
+ * @param pDev The device node.
+ * @param fOpen The open flags.
+ * @param pTd The thread.
+ * @param pFd The file descriptor. FreeBSD 7.0 and later.
+ * @param iFd The file descriptor index(?). Pre FreeBSD 7.0.
+ */
+#if __FreeBSD__ >= 7
+static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, struct thread *pTd, struct file *pFd)
+#else
+static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, struct thread *pTd, int iFd)
+#endif
+{
+ PSUPDRVSESSION pSession;
+ int rc;
+
+ dprintf(("VBoxDrvFreeBSDOpen: fOpen=%#x iUnit=%d\n", fOpen, minor2unit(minor(pDev))));
+
+ /*
+ * Let's be a bit picky about the flags...
+ */
+ if (fOpen != (FREAD|FWRITE /*=O_RDWR*/))
+ {
+ dprintf(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR));
+ return EINVAL;
+ }
+
+ /*
+ * Try grab it (we don't grab the giant, remember).
+ */
+ if (!ASMAtomicCmpXchgPtr(&pDev->si_drv1, (void *)0x42, NULL))
+ return EBUSY;
+
+ /*
+ * Create a new session.
+ */
+ rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, true /* fUser */, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo get (r)uid and (r)gid.
+ pSession->Uid = stuff;
+ pSession->Gid = stuff; */
+ if (ASMAtomicCmpXchgPtr(&pDev->si_drv1, pSession, (void *)0x42))
+ return 0;
+
+ OSDBGPRINT(("VBoxDrvFreeBSDOpen: si_drv1=%p, expected 0x42!\n", pDev->si_drv1));
+ supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession);
+ }
+
+ return RTErrConvertToErrno(rc);
+}
+
+
+/**
+ * Close a file device previously opened by VBoxDrvFreeBSDOpen
+ *
+ * @returns 0 on success.
+ * @param pDev The device.
+ * @param fFile The file descriptor flags.
+ * @param DevType The device type (CHR.
+ * @param pTd The calling thread.
+ */
+static int VBoxDrvFreeBSDClose(struct cdev *pDev, int fFile, int DevType, struct thread *pTd)
+{
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)pDev->si_drv1;
+ dprintf(("VBoxDrvFreeBSDClose: fFile=%#x iUnit=%d pSession=%p\n", fFile, minor2unit(minor(pDev)), pSession));
+
+ /*
+ * Close the session if it's still hanging on to the device...
+ */
+ if (VALID_PTR(pSession))
+ {
+ supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession);
+ if (!ASMAtomicCmpXchgPtr(&pDev->si_drv1, NULL, pSession))
+ OSDBGPRINT(("VBoxDrvFreeBSDClose: si_drv1=%p expected %p!\n", pDev->si_drv1, pSession));
+ }
+ else
+ OSDBGPRINT(("VBoxDrvFreeBSDClose: si_drv1=%p!\n", pSession));
+ return 0;
+}
+
+
+/**
+ * I/O control request.
+ *
+ * @returns depends...
+ * @param pDev The device.
+ * @param ulCmd The command.
+ * @param pvData Pointer to the data.
+ * @param fFile The file descriptor flags.
+ * @param pTd The calling thread.
+ */
+static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
+{
+ /*
+ * Validate the input.
+ */
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)pDev->si_drv1;
+ if (RT_UNLIKELY(!VALID_PTR(pSession)))
+ return EINVAL;
+
+ /*
+ * Deal with the fast ioctl path first.
+ */
+ if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || ulCmd == SUP_IOCTL_FAST_DO_NOP)
+ return supdrvIOCtlFast(ulCmd, *(uint32_t *)pvData, &g_VBoxDrvFreeBSDDevExt, pSession);
+
+ return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd);
+}
+
+
+/**
+ * Deal with the 'slow' I/O control requests.
+ *
+ * @returns 0 on success, appropriate errno on failure.
+ * @param pSession The session.
+ * @param ulCmd The command.
+ * @param pvData The request data.
+ * @param pTd The calling thread.
+ */
+static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
+{
+ PSUPREQHDR pHdr;
+ uint32_t cbReq = IOCPARM_LEN(ulCmd);
+ void *pvUser = NULL;
+
+ /*
+ * Buffered request?
+ */
+ if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
+ {
+ pHdr = (PSUPREQHDR)pvData;
+ if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
+ return EINVAL;
+ }
+ if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
+ return EINVAL;
+ }
+ if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
+ || pHdr->cbIn < sizeof(*pHdr)
+ || pHdr->cbOut < sizeof(*pHdr)))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
+ return EINVAL;
+ }
+ }
+ /*
+ * Big unbuffered request?
+ */
+ else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
+ {
+ /*
+ * Read the header, validate it and figure out how much that needs to be buffered.
+ */
+ SUPREQHDR Hdr;
+ pvUser = *(void **)pvData;
+ int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
+ if (RT_UNLIKELY(rc))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
+ return rc;
+ }
+ if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
+ return EINVAL;
+ }
+ cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
+ if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
+ || Hdr.cbOut < sizeof(Hdr)
+ || cbReq > _1M*16))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Allocate buffer and copy in the data.
+ */
+ pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
+ if (RT_UNLIKELY(!pHdr))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
+ return ENOMEM;
+ }
+ rc = copyin(pvUser, pHdr, Hdr.cbIn);
+ if (RT_UNLIKELY(rc))
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
+ pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
+ RTMemTmpFree(pHdr);
+ return rc;
+ }
+ }
+ else
+ {
+ dprintf(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr);
+ if (RT_LIKELY(!rc))
+ {
+ /*
+ * If unbuffered, copy back the result before returning.
+ */
+ if (pvUser)
+ {
+ uint32_t cbOut = pHdr->cbOut;
+ if (cbOut > cbReq)
+ {
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
+ cbOut = cbReq;
+ }
+ rc = copyout(pHdr, pvUser, cbOut);
+ if (RT_UNLIKELY(rc))
+ OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));
+
+ /* cleanup */
+ RTMemTmpFree(pHdr);
+ }
+ dprintf(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));
+ }
+ else
+ {
+ /*
+ * The request failed, just clean up.
+ */
+ if (pvUser)
+ RTMemTmpFree(pHdr);
+
+ dprintf(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
+ rc = EINVAL;
+ }
+
+ return rc;
+}
+
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code, see supdrvIDC.
+ * @param iReq The request code.
+ * @param pReq The request.
+ */
+int VBOXCALL SUPDrvFreeBSDIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Some quick validations.
+ */
+ if (RT_UNLIKELY(!VALID_PTR(pReq)))
+ return VERR_INVALID_POINTER;
+
+ pSession = pReq->pSession;
+ if (pSession)
+ {
+ if (RT_UNLIKELY(!VALID_PTR(pReq->pSession)))
+ return VERR_INVALID_PARAMETER;
+ if (RT_UNLIKELY(pSession->pDevExt != &g_VBoxDrvFreeBSDModule))
+ return VERR_INVALID_PARAMETER;
+ }
+ else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Do the job.
+ */
+ return supdrvIDC(uReq, &g_VBoxDrvFreeBSDModule, pSession, pReq);
+}
+
+
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ return false;
+}
+
+
+SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+ va_list va;
+ char szMsg[256];
+ int cch;
+
+ va_start(va, pszFormat);
+ cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
+ va_end(va);
+
+ printf("%s", szMsg);
+
+ return cch;
+}
+
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
new file mode 100644
index 000000000..6443b4619
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
@@ -0,0 +1,196 @@
+/* $Id: $ */
+/** @file
+ * VirtualBox Support Library - FreeBSD specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <VBox/types.h>
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** FreeBSD base device name. */
+#define DEVICE_NAME "/dev/vboxdrv"
+
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+
+ /*
+ * Try open the BSD device.
+ */
+ int hDevice = -1;
+ char szDevice[sizeof(DEVICE_NAME) + 16];
+ for (unsigned iUnit = 0; iUnit < 1024; iUnit++)
+ {
+ errno = 0;
+ RTStrPrintf(szDevice, sizeof(szDevice), DEVICE_NAME "%d", iUnit);
+ hDevice = open(szDevice, O_RDWR, 0);
+ if (hDevice >= 0 || errno != EBUSY)
+ break;
+ }
+ if (hDevice < 0)
+ {
+ int rc;
+ switch (errno)
+ {
+ case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
+ case EPERM:
+ case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
+ case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", szDevice, errno, rc));
+ return rc;
+ }
+
+ /*
+ * Mark the file handle close on exec.
+ */
+ if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) != 0)
+ {
+#ifdef IN_SUP_HARDENED_R3
+ int rc = VERR_INTERNAL_ERROR;
+#else
+ int err = errno;
+ int rc = RTErrConvertFromErrno(err);
+ LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d (%Rrc)\n", err, rc));
+#endif
+ close(hDevice);
+ return rc;
+ }
+
+ /*
+ * We're done.
+ */
+ pThis->hDevice = hDevice;
+ return VINF_SUCCESS;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Check if we're initited at all.
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ if (close(pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = NIL_RTFILE;
+ }
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsInstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsUninstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
+ return VINF_SUCCESS;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ int rc = ioctl(pThis->hDevice, uFunction, idCpu);
+ if (rc == -1)
+ rc = errno;
+ return rc;
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ NOREF(pThis);
+ *ppvPages = RTMemPageAllocZ(cPages << PAGE_SHIFT);
+ if (*ppvPages)
+ return VINF_SUCCESS;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
+{
+ NOREF(pThis);
+ RTMemPageFree(pvPages);
+ return VINF_SUCCESS;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPR0IdcClient-freebsd.c b/src/VBox/HostDrivers/Support/freebsd/SUPR0IdcClient-freebsd.c
new file mode 100644
index 000000000..f9d0000eb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPR0IdcClient-freebsd.c
@@ -0,0 +1,59 @@
+/* $Id: SUPR0IdcClient-freebsd.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, FreeBSD Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc = SUPDrvFreeBSDIDC(iReq, pReq);
+ if (RT_SUCCESS(rc))
+ rc = pReq->rc;
+
+ NOREF(pHandle);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile b/src/VBox/HostDrivers/Support/linux/Makefile
new file mode 100644
index 000000000..d58b9160f
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile
@@ -0,0 +1,282 @@
+#
+# Makefile for the VirtualBox Linux Host Driver.
+# (For 2.6.x this file must be called 'Makefile'!)
+#
+
+#
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+#
+# First, figure out which architecture we're targeting and the build type.
+# (We have to support basic cross building (ARCH=i386|x86_64).)
+# While at it, warn about BUILD_* vars found to help with user problems.
+#
+ifneq ($(filter-out amd64 x86,$(BUILD_TARGET_ARCH)),)
+ $(warning Ignoring unknown BUILD_TARGET_ARCH value '$(BUILD_TARGET_ARCH)'.)
+ BUILD_TARGET_ARCH :=
+endif
+ifeq ($(BUILD_TARGET_ARCH),)
+ ifeq ($(ARCH),x86_64)
+ BUILD_TARGET_ARCH := amd64
+ else
+ ifeq ($(ARCH),i386)
+ BUILD_TARGET_ARCH := x86
+ else
+ ifeq ($(filter-out x86_64 amd64 AMD64,$(shell uname -m)),)
+ BUILD_TARGET_ARCH := amd64
+ else
+ BUILD_TARGET_ARCH := x86
+ endif
+ endif
+ endif
+else
+ $(warning Using BUILD_TARGET_ARCH='$(BUILD_TARGET_ARCH)' from the $(origin BUILD_TARGET_ARCH).)
+endif
+
+ifneq ($(filter-out release profile debug strict,$(BUILD_TYPE)),)
+ $(warning Ignoring unknown BUILD_TYPE value '$(BUILD_TYPE)'.)
+ BUILD_TYPE :=
+endif
+ifeq ($(BUILD_TYPE),)
+ BUILD_TYPE := release
+else
+ $(warning Using BUILD_TYPE='$(BUILD_TYPE)' from the $(origin BUILD_TYPE).)
+endif
+
+# use vm_insert_page() API (if available) to map kernel pages to userland - better debugging
+# VBOX_USE_INSERT_PAGE = 1
+
+# override is required by the Debian guys
+override MODULE = vboxdrv
+OBJS = \
+ linux/SUPDrv-linux.o \
+ SUPDrv.o \
+ r0drv/alloc-r0drv.o \
+ r0drv/initterm-r0drv.o \
+ r0drv/memobj-r0drv.o \
+ r0drv/mpnotification-r0drv.o \
+ r0drv/powernotification-r0drv.o \
+ r0drv/linux/assert-r0drv-linux.o \
+ r0drv/linux/alloc-r0drv-linux.o \
+ r0drv/linux/initterm-r0drv-linux.o \
+ r0drv/linux/memobj-r0drv-linux.o \
+ r0drv/linux/mp-r0drv-linux.o \
+ r0drv/linux/mpnotification-r0drv-linux.o \
+ r0drv/linux/process-r0drv-linux.o \
+ r0drv/linux/semevent-r0drv-linux.o \
+ r0drv/linux/semeventmulti-r0drv-linux.o \
+ r0drv/linux/semfastmutex-r0drv-linux.o \
+ r0drv/linux/spinlock-r0drv-linux.o \
+ r0drv/linux/thread-r0drv-linux.o \
+ r0drv/linux/thread2-r0drv-linux.o \
+ r0drv/linux/time-r0drv-linux.o \
+ r0drv/linux/timer-r0drv-linux.o \
+ common/err/RTErrConvertFromErrno.o \
+ common/log/log.o \
+ common/log/logellipsis.o \
+ common/log/logrel.o \
+ common/log/logrelellipsis.o \
+ common/log/logcom.o \
+ common/log/logformat.o \
+ common/string/strformat.o \
+ common/string/strformatrt.o \
+ common/string/strformattype.o \
+ common/string/strprintf.o \
+ common/string/strtonum.o \
+ r0drv/linux/RTLogWriteDebugger-r0drv-linux.o \
+ generic/RTAssertShouldPanic-generic.o \
+ generic/RTLogWriteStdErr-stub-generic.o \
+ generic/RTLogWriteStdOut-stub-generic.o \
+ generic/RTLogWriteUser-generic.o \
+ VBox/log-vbox.o \
+ VBox/strformat-vbox.o
+ifeq ($(BUILD_TARGET_ARCH),x86)
+OBJS += math/gcc/divdi3.o \
+ math/gcc/moddi3.o \
+ math/gcc/qdivrem.o \
+ math/gcc/udivdi3.o \
+ math/gcc/divdi3.o \
+ math/gcc/umoddi3.o
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+OBJS += alloc/heapsimple.o
+endif
+
+ifneq ($(MAKECMDGOALS),clean)
+
+ifeq ($(KERNELRELEASE),)
+
+ #
+ # building from this directory
+ #
+
+ # kernel base directory
+ ifndef KERN_DIR
+ # build for the current kernel, version check
+ KERN_DIR := /lib/modules/$(shell uname -r)/build
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ KERN_DIR := /usr/src/linux
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: unable to find the sources of your current Linux kernel. \
+ Specify KERN_DIR=<directory> and run Make again)
+ endif
+ $(warning Warning: using /usr/src/linux as the source directory of your \
+ Linux kernel. If this is not correct, specify \
+ KERN_DIR=<directory> and run Make again.)
+ endif
+ # check if versions match -- works only for later 2.6 kernels
+ VBOX_KERN_VER := $(shell $(MAKE) -sC $(KERN_DIR) kernelrelease 2> /dev/null || true)
+ ifneq ($(VBOX_KERN_VER),)
+ ifneq ($(VBOX_KERN_VER),$(shell uname -r))
+ $(error Error: /usr/src/linux (version $(VBOX_KERN_VER)) does not match \
+ the current kernel (version $(shell uname -r)))
+ endif
+ endif
+ else
+ # build for a dedicated kernel, no version check
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: KERN_DIR does not point to a directory)
+ endif
+ endif
+
+ # includes
+ ifndef KERN_INCL
+ KERN_INCL = $(KERN_DIR)/include
+ endif
+ ifneq ($(shell if test -d $(KERN_INCL); then echo yes; fi),yes)
+ $(error Error: unable to find the include directory for your current Linux \
+ kernel. Specify KERN_INCL=<directory> and run Make again)
+ endif
+
+ # module install dir, only for current kernel
+ ifneq ($(filter install install_rpm,$(MAKECMDGOALS)),)
+ ifndef MODULE_DIR
+ MODULE_DIR_TST := /lib/modules/$(shell uname -r)
+ ifeq ($(shell if test -d $(MODULE_DIR_TST); then echo yes; fi),yes)
+ MODULE_DIR := $(MODULE_DIR_TST)/misc
+ else
+ $(error Unable to find the folder to install the support driver to)
+ endif
+ endif # MODULE_DIR unspecified
+ endif
+
+ # guess kernel version (24 or 26)
+ KERN_VERSION := $(if $(wildcard $(KERN_DIR)/Rules.make),24,26)
+
+else # neq($(KERNELRELEASE),)
+
+ #
+ # building from kbuild (make -C <kernel_directory> M=`pwd`)
+ #
+
+ # guess kernel version (24 or 26)
+ KERN_VERSION := $(if $(wildcard $(PWD)/Rules.make),24,26)
+
+endif # neq($(KERNELRELEASE),)
+
+# debug - show guesses.
+ifdef DEBUG
+$(warning dbg: KERN_DIR = $(KERN_DIR))
+$(warning dbg: KERN_INCL = $(KERN_INCL))
+$(warning dbg: MODULE_DIR = $(MODULE_DIR))
+$(warning dbg: KERN_VERSION = $(KERN_VERSION))
+endif
+
+KBUILD_VERBOSE ?= 1
+
+#
+# Compiler options
+#
+ifndef INCL
+ INCL := $(addprefix -I,$(KERN_INCL) $(EXTRA_INCL))
+ ifndef KBUILD_EXTMOD
+ KBUILD_EXTMOD := $(shell pwd)
+ endif
+ INCL += $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux)
+ export INCL
+endif
+KFLAGS := -D__KERNEL__ -DMODULE -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 -DIN_SUP_R0 -DVBOX -DRT_WITH_VBOX -DVBOX_WITH_HARDENING
+ifdef VBOX_REDHAT_KABI
+ KFLAGS += -DVBOX_REDHAT_KABI
+endif
+ifndef CONFIG_VBOXDRV_FIXEDMAJOR
+ KFLAGS += -DCONFIG_VBOXDRV_AS_MISC
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ KFLAGS += -DRT_ARCH_AMD64
+else
+ KFLAGS += -DRT_ARCH_X86
+endif
+# must be consistent with Config.kmk!
+KFLAGS += -DVBOX_WITH_64_BITS_GUESTS
+ifeq ($(BUILD_TYPE),debug)
+ KFLAGS += -DDEBUG -DDEBUG_$(USER) -g
+ # IPRT_DEBUG_SEMS indicates thread wrt sems state via the comm field.
+ KFLAGS += -DIPRT_DEBUG_SEMS
+endif
+
+# By default we use remap_pfn_range() kernel API to make kernel pages
+# visible for userland. Unfortuately, it leads to situation that
+# during debug session all structures on that page (such as PVM pointer)
+# are not accessible to the debugger (see #3214).
+# This code enables experimental support
+# for vm_insert_page() kernel API, allowing to export kernel pages
+# to the userland in more debugger-friendly way. Due to stability
+# concerns, not enabled by default yet.
+ifdef VBOX_USE_INSERT_PAGE
+ KFLAGS += -DVBOX_USE_INSERT_PAGE
+endif
+
+# 2.6 and later
+MODULE_EXT := ko
+$(MODULE)-y := $(OBJS)
+
+# build defs
+EXTRA_CFLAGS += $(INCL) $(KFLAGS) $(KDEBUG)
+
+all: $(MODULE)
+
+obj-m += $(MODULE).o
+
+$(MODULE):
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) modules
+
+install: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0664 -o root -g root $(MODULE).$(MODULE_EXT) $(MODULE_DIR); \
+ PATH="$(PATH):/bin:/sbin" depmod -ae; \
+ rm -f /etc/vbox/module_not_compiled
+
+install_rpm: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0664 $(MODULE).$(MODULE_EXT) $(MODULE_DIR)
+
+endif # eq($(MAKECMDGOALS),clean)
+
+clean:
+ for f in . linux r0drv r0drv/linux VBox common/err common/string common/log generic math/gcc; \
+ do rm -f $$f/*.o $$f/.*.cmd $$f/.*.flags; done
+ rm -rf .vboxdrv* .tmp_ver* vboxdrv.* Module.symvers Modules.symvers modules.order
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile.kup b/src/VBox/HostDrivers/Support/linux/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
new file mode 100644
index 000000000..7fa74a1b6
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
@@ -0,0 +1,1089 @@
+/* $Rev: 15999 $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ * Some lines of code to disable the local APIC on x86_64 machines taken
+ * from a Mandriva patch by Gwenole Beauchesne <gbeauchesne@mandriva.com>.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#include "../SUPDrvInternal.h"
+#include "the-linux-kernel.h"
+#include "version-generated.h"
+
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <VBox/log.h>
+#include <iprt/mp.h>
+
+/** @todo figure out the exact version number */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
+# include <iprt/power.h>
+# define VBOX_WITH_SUSPEND_NOTIFICATION
+#endif
+
+#include <linux/sched.h>
+#ifdef CONFIG_DEVFS_FS
+# include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef CONFIG_VBOXDRV_AS_MISC
+# include <linux/miscdevice.h>
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+# include <asm/apic.h>
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# include <asm/nmi.h>
+# endif
+#endif
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+# include <linux/platform_device.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+# include <asm/pgtable.h>
+# define global_flush_tlb __flush_tlb_global
+#endif
+
+#include <iprt/mem.h>
+
+
+/* devfs defines */
+#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
+# ifdef VBOX_WITH_HARDENING
+# define VBOX_DEV_FMASK (S_IWUSR | S_IRUSR)
+# else
+# define VBOX_DEV_FMASK (S_IRUGO | S_IWUGO)
+# endif
+
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+# define VBOX_REGISTER_DEVFS() \
+({ \
+ void *rc = NULL; \
+ if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), \
+ S_IFCHR | VBOX_DEV_FMASK, \
+ DEVICE_NAME) == 0) \
+ rc = (void *)' '; /* return not NULL */ \
+ rc; \
+ })
+
+# define VBOX_UNREGISTER_DEVFS(handle) \
+ devfs_remove(DEVICE_NAME);
+
+# else /* < 2.6.0 */
+
+# define VBOX_REGISTER_DEVFS() \
+ devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, \
+ DEVICE_MAJOR, 0, \
+ S_IFCHR | VBOX_DEV_FMASK, \
+ &gFileOpsVBoxDrv, NULL)
+
+# define VBOX_UNREGISTER_DEVFS(handle) \
+ if (handle != NULL) \
+ devfs_unregister(handle)
+
+# endif /* < 2.6.0 */
+#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
+
+#ifndef CONFIG_VBOXDRV_AS_MISC
+# if defined(CONFIG_DEVFS_FS) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 0)
+# define VBOX_REGISTER_DEVICE(a,b,c) devfs_register_chrdev(a,b,c)
+# define VBOX_UNREGISTER_DEVICE(a,b) devfs_unregister_chrdev(a,b)
+# else
+# define VBOX_REGISTER_DEVICE(a,b,c) register_chrdev(a,b,c)
+# define VBOX_UNREGISTER_DEVICE(a,b) unregister_chrdev(a,b)
+# endif
+#endif /* !CONFIG_VBOXDRV_AS_MISC */
+
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+/* If an NMI occurs while we are inside the world switcher the machine will
+ * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter
+ * which is compared with another counter increased in the timer interrupt
+ * handler. We disable the NMI watchdog.
+ *
+ * - Linux >= 2.6.21: The watchdog is disabled by default on i386 and x86_64.
+ * - Linux < 2.6.21: The watchdog is normally enabled by default on x86_64
+ * and disabled on i386.
+ */
+# if defined(RT_ARCH_AMD64)
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) && !defined(VBOX_REDHAT_KABI)
+# define DO_DISABLE_NMI 1
+# endif
+# endif
+
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+extern int nmi_active;
+# define nmi_atomic_read(P) *(P)
+# define nmi_atomic_set(P, V) *(P) = (V)
+# define nmi_atomic_dec(P) nmi_atomic_set(P, 0)
+# else
+# define nmi_atomic_read(P) atomic_read(P)
+# define nmi_atomic_set(P, V) atomic_set(P, V)
+# define nmi_atomic_dec(P) atomic_dec(P)
+# endif
+
+# ifndef X86_FEATURE_ARCH_PERFMON
+# define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
+# endif
+# ifndef MSR_ARCH_PERFMON_EVENTSEL0
+# define MSR_ARCH_PERFMON_EVENTSEL0 0x186
+# endif
+# ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT
+# define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
+# endif
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Device extention & session data association structure.
+ */
+static SUPDRVDEVEXT g_DevExt;
+
+/** Registered devfs device handle. */
+#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+static void *g_hDevFsVBoxDrv = NULL;
+# else
+static devfs_handle_t g_hDevFsVBoxDrv = NULL;
+# endif
+#endif
+
+#ifndef CONFIG_VBOXDRV_AS_MISC
+/** Module major number */
+#define DEVICE_MAJOR 234
+/** Saved major device number */
+static int g_iModuleMajor;
+#endif /* !CONFIG_VBOXDRV_AS_MISC */
+
+/** Module parameter.
+ * Not prefixed because the name is used by macros and the end of this file. */
+static int force_async_tsc = 0;
+
+/** The module name. */
+#define DEVICE_NAME "vboxdrv"
+
+#ifdef RT_ARCH_AMD64
+/**
+ * Memory for the executable memory heap (in IPRT).
+ */
+extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
+__asm__(".section execmemory, \"awx\", @progbits\n\t"
+ ".align 32\n\t"
+ ".globl g_abExecMemory\n"
+ "g_abExecMemory:\n\t"
+ ".zero 1572864\n\t"
+ ".type g_abExecMemory, @object\n\t"
+ ".size g_abExecMemory, 1572864\n\t"
+ ".text\n\t");
+#endif
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int VBoxDrvLinuxInit(void);
+static void VBoxDrvLinuxUnload(void);
+static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp);
+static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
+#ifdef HAVE_UNLOCKED_IOCTL
+static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#else
+static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#endif
+static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+static int VBoxDrvLinuxErr2LinuxErr(int);
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+static int VBoxDrvProbe(struct platform_device *pDev);
+static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
+static int VBoxDrvResume(struct platform_device *pDev);
+static void VBoxDevRelease(struct device *pDev);
+#endif
+
+/** The file_operations structure. */
+static struct file_operations gFileOpsVBoxDrv =
+{
+ owner: THIS_MODULE,
+ open: VBoxDrvLinuxCreate,
+ release: VBoxDrvLinuxClose,
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: VBoxDrvLinuxIOCtl,
+#else
+ ioctl: VBoxDrvLinuxIOCtl,
+#endif
+};
+
+#ifdef CONFIG_VBOXDRV_AS_MISC
+/** The miscdevice structure. */
+static struct miscdevice gMiscDevice =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: DEVICE_NAME,
+ fops: &gFileOpsVBoxDrv,
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && \
+ LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
+ devfs_name: DEVICE_NAME,
+# endif
+};
+#endif
+
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+static struct platform_driver gPlatformDriver =
+{
+ .probe = VBoxDrvProbe,
+ .suspend = VBoxDrvSuspend,
+ .resume = VBoxDrvResume,
+ /** @todo .shutdown? */
+ .driver =
+ {
+ .name = "vboxdrv"
+ }
+};
+
+static struct platform_device gPlatformDevice =
+{
+ .name = "vboxdrv",
+ .dev =
+ {
+ .release = VBoxDevRelease
+ }
+};
+#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
+
+
+#ifdef CONFIG_X86_LOCAL_APIC
+# ifdef DO_DISABLE_NMI
+/** Stop AMD NMI watchdog (x86_64 only). */
+static int vboxdrvStopK7Watchdog(void)
+{
+ wrmsr(MSR_K7_EVNTSEL0, 0, 0);
+ return 1;
+}
+
+/** Stop Intel P4 NMI watchdog (x86_64 only). */
+static int vboxdrvStopP4Watchdog(void)
+{
+ wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+ wrmsr(MSR_P4_IQ_CCCR1, 0, 0);
+ wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+ return 1;
+}
+
+/** The new method of detecting the event counter */
+static int vboxdrvStopIntelArchWatchdog(void)
+{
+ unsigned ebx;
+
+ ebx = cpuid_ebx(10);
+ if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+ wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
+ return 1;
+}
+
+/** Stop NMI watchdog. */
+static void vboxdrvStopApicNmiWatchdog(void *unused)
+{
+ int stopped = 0;
+
+ /* only support LOCAL and IO APICs for now */
+ if ((nmi_watchdog != NMI_LOCAL_APIC) &&
+ (nmi_watchdog != NMI_IO_APIC))
+ return;
+
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ {
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_AMD:
+ if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
+ return;
+ stopped = vboxdrvStopK7Watchdog();
+ break;
+ case X86_VENDOR_INTEL:
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
+ {
+ stopped = vboxdrvStopIntelArchWatchdog();
+ break;
+ }
+ stopped = vboxdrvStopP4Watchdog();
+ break;
+ default:
+ return;
+ }
+ }
+
+ if (stopped)
+ nmi_atomic_dec(&nmi_active);
+}
+
+/** Disable LAPIC NMI watchdog. */
+static void DisableLapicNmiWatchdog(void)
+{
+ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+ if (nmi_atomic_read(&nmi_active) <= 0)
+ return;
+
+ on_each_cpu(vboxdrvStopApicNmiWatchdog, NULL, 1, 1);
+
+ BUG_ON(nmi_atomic_read(&nmi_active) != 0);
+
+ /* tell do_nmi() and others that we're not active any more */
+ nmi_watchdog = NMI_NONE;
+}
+
+/** Shutdown NMI. */
+static void vboxdrvNmiCpuShutdown(void * dummy)
+{
+ unsigned int vERR, vPC;
+
+ vPC = apic_read(APIC_LVTPC);
+
+ if ((GET_APIC_DELIVERY_MODE(vPC) == APIC_MODE_NMI) && !(vPC & APIC_LVT_MASKED))
+ {
+ vERR = apic_read(APIC_LVTERR);
+ apic_write(APIC_LVTERR, vERR | APIC_LVT_MASKED);
+ apic_write(APIC_LVTPC, vPC | APIC_LVT_MASKED);
+ apic_write(APIC_LVTERR, vERR);
+ }
+}
+
+static void vboxdrvNmiShutdown(void)
+{
+ on_each_cpu(vboxdrvNmiCpuShutdown, NULL, 0, 1);
+}
+# endif /* DO_DISABLE_NMI */
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+
+DECLINLINE(RTUID) vboxdrvLinuxUid(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+ return current->cred->uid;
+#else
+ return current->uid;
+#endif
+}
+
+DECLINLINE(RTGID) vboxdrvLinuxGid(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+ return current->cred->gid;
+#else
+ return current->gid;
+#endif
+}
+
+DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+ return current->cred->euid;
+#else
+ return current->euid;
+#endif
+}
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxDrvLinuxInit(void)
+{
+ int rc;
+
+ dprintf(("VBoxDrv::ModuleInit\n"));
+
+#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * If an NMI occurs while we are inside the world switcher the macine will crash.
+ * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
+ * compared with another counter increased in the timer interrupt handler. Therefore
+ * we don't allow to setup an NMI watchdog.
+ */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
+ /*
+ * First test: NMI actiated? Works only works with Linux 2.6 -- 2.4 does not export
+ * the nmi_watchdog variable.
+ */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
+ (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+# ifdef DO_DISABLE_NMI
+ if (nmi_atomic_read(&nmi_active) > 0)
+ {
+ printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog...\n");
+
+ switch (nmi_watchdog)
+ {
+ case NMI_LOCAL_APIC:
+ DisableLapicNmiWatchdog();
+ break;
+ case NMI_NONE:
+ nmi_atomic_dec(&nmi_active);
+ break;
+ }
+
+ if (nmi_atomic_read(&nmi_active) == 0)
+ {
+ vboxdrvNmiShutdown();
+ printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
+ }
+ else
+ printk(KERN_DEBUG DEVICE_NAME ": Failed!\n");
+ }
+# endif /* DO_DISABLE_NMI */
+
+ /*
+ * Permanent IO_APIC mode active? No way to handle this!
+ */
+ if (nmi_watchdog == NMI_IO_APIC)
+ {
+ printk(KERN_ERR DEVICE_NAME
+ ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"
+ DEVICE_NAME
+ ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"
+ DEVICE_NAME
+ ": command line.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * See arch/i386/kernel/nmi.c on >= 2.6.19: -1 means it can never enabled again
+ */
+ nmi_atomic_set(&nmi_active, -1);
+ printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog permanently...\n");
+
+ /*
+ * Now fall through and see if it actually was enabled before. If so, fail
+ * as we cannot deactivate it cleanly from here.
+ */
+# else /* < 2.6.19 */
+ /*
+ * Older 2.6 kernels: nmi_watchdog is not initalized by default
+ */
+ if (nmi_watchdog != NMI_NONE)
+ goto nmi_activated;
+# endif
+# endif /* >= 2.6.0 && !defined(VBOX_REDHAT_KABI) */
+
+ /*
+ * Second test: Interrupt generated by performance counter not masked and can
+ * generate an NMI. Works also with Linux 2.4.
+ */
+ {
+ unsigned int v, ver, maxlvt;
+
+ v = apic_read(APIC_LVR);
+ ver = GET_APIC_VERSION(v);
+ /* 82489DXs do not report # of LVT entries. */
+ maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
+ if (maxlvt >= 4)
+ {
+ /* Read status of performance counter IRQ vector */
+ v = apic_read(APIC_LVTPC);
+
+ /* performance counter generates NMI and is not masked? */
+ if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
+ {
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
+ (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+ printk(KERN_ERR DEVICE_NAME
+ ": NMI watchdog either active or at least initialized. Please disable the NMI\n"
+ DEVICE_NAME
+ ": watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
+ return -EINVAL;
+# else /* < 2.6.19 */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
+nmi_activated:
+# endif
+ printk(KERN_ERR DEVICE_NAME
+ ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
+ DEVICE_NAME
+ ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
+ return -EINVAL;
+# endif /* >= 2.6.19 */
+ }
+ }
+ }
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
+# endif /* >= 2.6.19 */
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+ /*
+ * Check for synchronous/asynchronous TSC mode.
+ */
+ printk(KERN_DEBUG DEVICE_NAME ": Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount());
+#ifdef CONFIG_VBOXDRV_AS_MISC
+ rc = misc_register(&gMiscDevice);
+ if (rc)
+ {
+ printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
+ return rc;
+ }
+#else /* !CONFIG_VBOXDRV_AS_MISC */
+ /*
+ * Register character device.
+ */
+ g_iModuleMajor = DEVICE_MAJOR;
+ rc = VBOX_REGISTER_DEVICE((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
+ if (rc < 0)
+ {
+ dprintf(("VBOX_REGISTER_DEVICE failed with rc=%#x!\n", rc));
+ return rc;
+ }
+
+ /*
+ * Save returned module major number
+ */
+ if (DEVICE_MAJOR != 0)
+ g_iModuleMajor = DEVICE_MAJOR;
+ else
+ g_iModuleMajor = rc;
+ rc = 0;
+
+#ifdef CONFIG_DEVFS_FS
+ /*
+ * Register a device entry
+ */
+ g_hDevFsVBoxDrv = VBOX_REGISTER_DEVFS();
+ if (g_hDevFsVBoxDrv == NULL)
+ {
+ dprintf(("devfs_register failed!\n"));
+ rc = -EINVAL;
+ }
+#endif
+#endif /* !CONFIG_VBOXDRV_AS_MISC */
+ if (!rc)
+ {
+ /*
+ * Initialize the runtime.
+ * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef RT_ARCH_AMD64
+ rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
+ printk("VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
+#endif
+ /*
+ * Initialize the device extension.
+ */
+ if (RT_SUCCESS(rc))
+ rc = supdrvInitDevExt(&g_DevExt);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ rc = platform_driver_register(&gPlatformDriver);
+ if (rc == 0)
+ {
+ rc = platform_device_register(&gPlatformDevice);
+ if (rc == 0)
+#endif
+ {
+ printk(KERN_INFO DEVICE_NAME ": TSC mode is %s, kernel timer mode is "
+#ifdef VBOX_HRTIMER
+ "'high-res'"
+#else
+ "'normal'"
+#endif
+ ".\n",
+ g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
+ LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
+ printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
+ VBOX_VERSION_STRING " (interface " xstr(SUPDRV_IOC_VERSION) ").\n");
+ return rc;
+ }
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ else
+ platform_driver_unregister(&gPlatformDriver);
+ }
+#endif
+ }
+
+ rc = -EINVAL;
+ RTR0Term();
+ }
+ else
+ rc = -EINVAL;
+
+ /*
+ * Failed, cleanup and return the error code.
+ */
+#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
+ VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
+#endif
+ }
+#ifdef CONFIG_VBOXDRV_AS_MISC
+ misc_deregister(&gMiscDevice);
+ dprintf(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
+#else
+ VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
+ dprintf(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
+#endif
+ return rc;
+}
+
+
+/**
+ * Unload the module.
+ */
+static void __exit VBoxDrvLinuxUnload(void)
+{
+ int rc;
+ dprintf(("VBoxDrvLinuxUnload\n"));
+ NOREF(rc);
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ platform_device_unregister(&gPlatformDevice);
+ platform_driver_unregister(&gPlatformDriver);
+#endif
+
+ /*
+ * I Don't think it's possible to unload a driver which processes have
+ * opened, at least we'll blindly assume that here.
+ */
+#ifdef CONFIG_VBOXDRV_AS_MISC
+ rc = misc_deregister(&gMiscDevice);
+ if (rc < 0)
+ {
+ dprintf(("misc_deregister failed with rc=%#x\n", rc));
+ }
+#else /* !CONFIG_VBOXDRV_AS_MISC */
+# ifdef CONFIG_DEVFS_FS
+ /*
+ * Unregister a device entry
+ */
+ VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
+# endif /* devfs */
+ VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
+#endif /* !CONFIG_VBOXDRV_AS_MISC */
+
+ /*
+ * Destroy GIP, delete the device extension and terminate IPRT.
+ */
+ supdrvDeleteDevExt(&g_DevExt);
+ RTR0Term();
+}
+
+
+/**
+ * Device open. Called on open /dev/vboxdrv
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp)
+{
+ int rc;
+ PSUPDRVSESSION pSession;
+ Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Only root is allowed to access the device, enforce it!
+ */
+ if (vboxdrvLinuxEuid() != 0 /* root */ )
+ {
+ Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
+ return -EPERM;
+ }
+#endif /* VBOX_WITH_HARDENING */
+
+ /*
+ * Call common code for the rest.
+ */
+ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, (PSUPDRVSESSION *)&pSession);
+ if (!rc)
+ {
+ pSession->Uid = vboxdrvLinuxUid();
+ pSession->Gid = vboxdrvLinuxGid();
+ }
+
+ pFilp->private_data = pSession;
+
+ Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
+ &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
+ RTProcSelf(), current->pid, current->comm));
+ return VBoxDrvLinuxErr2LinuxErr(rc);
+}
+
+
+/**
+ * Close device.
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
+{
+ Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
+ pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
+ supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
+ pFilp->private_data = NULL;
+ return 0;
+}
+
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+/**
+ * Dummy device release function. We have to provide this function,
+ * otherwise the kernel will complain.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+static void VBoxDevRelease(struct device *pDev)
+{
+}
+
+/**
+ * Dummy probe function.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+static int VBoxDrvProbe(struct platform_device *pDev)
+{
+ return 0;
+}
+
+/**
+ * Suspend callback.
+ * @param pDev Pointer to the platform device.
+ * @param State message type, see Documentation/power/devices.txt.
+ */
+static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
+{
+ RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
+ return 0;
+}
+
+/**
+ * Resume callback.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+static int VBoxDrvResume(struct platform_device *pDev)
+{
+ RTPowerSignalEvent(RTPOWEREVENT_RESUME);
+ return 0;
+}
+#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ */
+#ifdef HAVE_UNLOCKED_IOCTL
+static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#else
+static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#endif
+{
+ /*
+ * Deal with the two high-speed IOCtl that takes it's arguments from
+ * the session and iCmd, and only returns a VBox status code.
+ */
+#ifdef HAVE_UNLOCKED_IOCTL
+ if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || uCmd == SUP_IOCTL_FAST_DO_NOP))
+ return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
+ return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
+
+#else /* !HAVE_UNLOCKED_IOCTL */
+
+ int rc;
+ unlock_kernel();
+ if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || uCmd == SUP_IOCTL_FAST_DO_NOP))
+ rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
+ else
+ rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
+ lock_kernel();
+ return rc;
+#endif /* !HAVE_UNLOCKED_IOCTL */
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ */
+static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+{
+ int rc;
+ SUPREQHDR Hdr;
+ PSUPREQHDR pHdr;
+ uint32_t cbBuf;
+
+ Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
+
+ /*
+ * Read the header.
+ */
+ if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
+ {
+ Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
+ return -EFAULT;
+ }
+ if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
+ return -EINVAL;
+ }
+
+ /*
+ * Buffer the request.
+ */
+ cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
+ if (RT_UNLIKELY(cbBuf > _1M*16))
+ {
+ Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
+ return -E2BIG;
+ }
+ if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
+ {
+ Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
+ return -EINVAL;
+ }
+ pHdr = RTMemAlloc(cbBuf);
+ if (RT_UNLIKELY(!pHdr))
+ {
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
+ return -ENOMEM;
+ }
+ if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
+ {
+ Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
+ RTMemFree(pHdr);
+ return -EFAULT;
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr);
+
+ /*
+ * Copy ioctl data and output buffer back to user space.
+ */
+ if (RT_LIKELY(!rc))
+ {
+ uint32_t cbOut = pHdr->cbOut;
+ if (RT_UNLIKELY(cbOut > cbBuf))
+ {
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
+ cbOut = cbBuf;
+ }
+ if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
+ {
+ /* this is really bad! */
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
+ rc = -EFAULT;
+ }
+ }
+ else
+ {
+ Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
+ rc = -EINVAL;
+ }
+ RTMemFree(pHdr);
+
+ Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
+ return rc;
+}
+
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code, see supdrvIDC.
+ * @param iReq The request code.
+ * @param pReq The request.
+ */
+int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Some quick validations.
+ */
+ if (RT_UNLIKELY(!VALID_PTR(pReq)))
+ return VERR_INVALID_POINTER;
+
+ pSession = pReq->pSession;
+ if (pSession)
+ {
+ if (RT_UNLIKELY(!VALID_PTR(pSession)))
+ return VERR_INVALID_PARAMETER;
+ if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
+ return VERR_INVALID_PARAMETER;
+ }
+ else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Do the job.
+ */
+ return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
+}
+
+EXPORT_SYMBOL(SUPDrvLinuxIDC);
+
+
+/**
+ * Initializes any OS specific object creator fields.
+ */
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+/**
+ * Checks if the session can access the object.
+ *
+ * @returns true if a decision has been made.
+ * @returns false if the default access policy should be applied.
+ *
+ * @param pObj The object in question.
+ * @param pSession The session wanting to access the object.
+ * @param pszObjName The object name, can be NULL.
+ * @param prc Where to store the result when returning true.
+ */
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ return force_async_tsc != 0;
+}
+
+
+/**
+ * Converts a supdrv error code to an linux error code.
+ *
+ * @returns corresponding linux error code.
+ * @param rc supdrv error code (SUPDRV_ERR_* defines).
+ */
+static int VBoxDrvLinuxErr2LinuxErr(int rc)
+{
+ switch (rc)
+ {
+ case 0: return 0;
+ case SUPDRV_ERR_GENERAL_FAILURE: return -EACCES;
+ case SUPDRV_ERR_INVALID_PARAM: return -EINVAL;
+ case SUPDRV_ERR_INVALID_MAGIC: return -EILSEQ;
+ case SUPDRV_ERR_INVALID_HANDLE: return -ENXIO;
+ case SUPDRV_ERR_INVALID_POINTER: return -EFAULT;
+ case SUPDRV_ERR_LOCK_FAILED: return -ENOLCK;
+ case SUPDRV_ERR_ALREADY_LOADED: return -EEXIST;
+ case SUPDRV_ERR_PERMISSION_DENIED: return -EPERM;
+ case SUPDRV_ERR_VERSION_MISMATCH: return -ENOSYS;
+ case SUPDRV_ERR_IDT_FAILED: return -1000;
+ }
+
+ return -EPERM;
+}
+
+
+RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+#if 1
+ va_list args;
+ char szMsg[512];
+
+ va_start(args, pszFormat);
+ vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ printk("%s", szMsg);
+ va_end(args);
+#else
+ /* forward to printf - needs some more GCC hacking to fix ebp... */
+ __asm__ __volatile__ ("mov %0, %esp\n\t"
+ "jmp %1\n\t",
+ :: "r" ((uintptr_t)&pszFormat - 4),
+ "m" (printk));
+#endif
+ return 0;
+}
+
+module_init(VBoxDrvLinuxInit);
+module_exit(VBoxDrvLinuxUnload);
+
+MODULE_AUTHOR("Sun Microsystems, Inc.");
+MODULE_DESCRIPTION("VirtualBox Support Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " (" xstr(SUPDRV_IOC_VERSION) ")");
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+module_param(force_async_tsc, int, 0444);
+#else
+MODULE_PARM(force_async_tsc, "i");
+#endif
+MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c
new file mode 100644
index 000000000..40a54909a
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c
@@ -0,0 +1,94 @@
+/* $Id: SUPDrv-linux.mod.c 10662 2008-07-15 14:36:00Z vboxsync $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Autogenerated Linux code.
+ * This is checked in to assist syntax checking the module.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#include "SUPDrvInternal.h" /* for KBUILD_STR */
+#include "the-linux-kernel.h"
+#include <linux/vermagic.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+#undef unix
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = __stringify(KBUILD_MODNAME),
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+};
+
+static const struct modversion_info ____versions[]
+__attribute_used__
+__attribute__((section("__versions"))) = {
+ { 0, "cleanup_module" },
+ { 0, "init_module" },
+ { 0, "struct_module" },
+ { 0, "devfs_remove" },
+ { 0, "strpbrk" },
+ { 0, "__kmalloc" },
+ { 0, "mem_map" },
+ { 0, "vmalloc" },
+ { 0, "malloc_sizes" },
+ { 0, "vfree" },
+ { 0, "change_page_attr" },
+ { 0, "__might_sleep" },
+ { 0, "remap_page_range" },
+ { 0, "__alloc_pages" },
+ { 0, "printk" },
+ { 0, "__PAGE_KERNEL" },
+ { 0, "rwsem_wake" },
+ { 0, "copy_to_user" },
+ { 0, "devfs_mk_cdev" },
+ { 0, "preempt_schedule" },
+ { 0, "contig_page_data" },
+ { 0, "do_mmap_pgoff" },
+ { 0, "find_vma" },
+ { 0, "kmem_cache_alloc" },
+ { 0, "__free_pages" },
+ { 0, "do_munmap" },
+ { 0, "get_user_pages" },
+ { 0, "register_chrdev" },
+ { 0, "vsnprintf" },
+ { 0, "kfree" },
+ { 0, "memcpy" },
+ { 0, "unregister_chrdev" },
+ { 0, "put_page" },
+ { 0, "__up_wakeup" },
+ { 0, "__down_failed" },
+ { 0, "copy_from_user" },
+ { 0, "rwsem_down_read_failed" },
+};
+
+static const char __module_depends[]
+__attribute_used__
+__attribute__((section(".modinfo"))) =
+"depends=";
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
new file mode 100644
index 000000000..c02beae38
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
@@ -0,0 +1,255 @@
+/* $Id: SUPLib-linux.cpp 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - GNU/Linux specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <VBox/log.h>
+#include <VBox/sup.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <VBox/types.h>
+#include <iprt/string.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Unix Device name. */
+#define DEVICE_NAME "/dev/vboxdrv"
+
+/* define MADV_DONTFORK if it's missing from the system headers. */
+#ifndef MADV_DONTFORK
+# define MADV_DONTFORK 10
+#endif
+
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+ Assert(pThis->hDevice == NIL_RTFILE);
+
+ /*
+ * Check if madvise works.
+ */
+ void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pv == MAP_FAILED)
+ return VERR_NO_MEMORY;
+ pThis->fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
+ munmap(pv, PAGE_SIZE);
+
+ /*
+ * Try open the device.
+ */
+ int hDevice = open(DEVICE_NAME, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ /*
+ * Try load the device.
+ */
+ hDevice = open(DEVICE_NAME, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ int rc;
+ switch (errno)
+ {
+ case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
+ case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
+ case EPERM:
+ case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
+ case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", DEVICE_NAME, errno, rc));
+ return rc;
+ }
+ }
+
+ /*
+ * Mark the file handle close on exec.
+ */
+ if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ close(hDevice);
+#ifdef IN_SUP_HARDENED_R3
+ return VERR_INTERNAL_ERROR;
+#else
+ return RTErrConvertFromErrno(errno);
+#endif
+ }
+
+ /*
+ * We're done.
+ */
+ pThis->hDevice = hDevice;
+ return VINF_SUCCESS;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Close the device if it's actually open.
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ if (close(pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = NIL_RTFILE;
+ }
+
+ return 0;
+}
+
+
+int suplibOsInstall(void)
+{
+ // nothing to do on Linux
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsUninstall(void)
+{
+ // nothing to do on Linux
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ AssertMsg(pThis->hDevice != NIL_RTFILE, ("SUPLIB not initiated successfully!\n"));
+
+ /*
+ * Issue device iocontrol.
+ */
+ if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
+ return VINF_SUCCESS;
+
+ /* This is the reverse operation of the one found in SUPDrv-linux.c */
+ switch (errno)
+ {
+ case EACCES: return VERR_GENERAL_FAILURE;
+ case EINVAL: return VERR_INVALID_PARAMETER;
+ case EILSEQ: return VERR_INVALID_MAGIC;
+ case ENXIO: return VERR_INVALID_HANDLE;
+ case EFAULT: return VERR_INVALID_POINTER;
+ case ENOLCK: return VERR_LOCK_FAILED;
+ case EEXIST: return VERR_ALREADY_LOADED;
+ case EPERM: return VERR_PERMISSION_DENIED;
+ case ENOSYS: return VERR_VERSION_MISMATCH;
+ case 1000: return VERR_IDT_FAILED;
+ }
+
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ int rc = ioctl(pThis->hDevice, uFunction, idCpu);
+ if (rc == -1)
+ rc = -errno;
+ return rc;
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ size_t cbMmap = (pThis->fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
+ char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pvPages == MAP_FAILED)
+ return VERR_NO_MEMORY;
+
+ if (pThis->fSysMadviseWorks)
+ {
+ /*
+ * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
+ * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
+ * kernel seems to split bigger VMAs and that is all that we want -- later we set the
+ * VM_DONTCOPY attribute in supdrvOSLockMemOne().
+ */
+ if (madvise (pvPages, cbMmap, MADV_DONTFORK))
+ LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
+ *ppvPages = pvPages;
+ }
+ else
+ {
+ /*
+ * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
+ * mmapped region by two unmapped pages to guarantee that there is exactly one VM
+ * area struct of the very same size as the mmap area.
+ */
+ mprotect(pvPages, PAGE_SIZE, PROT_NONE);
+ mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
+ *ppvPages = pvPages + PAGE_SIZE;
+ }
+ memset(*ppvPages, 0, cPages << PAGE_SHIFT);
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages)
+{
+ munmap(pvPages, cPages << PAGE_SHIFT);
+ return VINF_SUCCESS;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c b/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c
new file mode 100644
index 000000000..90abb0a92
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c
@@ -0,0 +1,59 @@
+/* $Id: SUPR0IdcClient-linux.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Linux Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc = SUPDrvLinuxIDC(iReq, pReq);
+ if (RT_SUCCESS(rc))
+ rc = pReq->rc;
+
+ NOREF(pHandle);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/linux/dkms.conf b/src/VBox/HostDrivers/Support/linux/dkms.conf
new file mode 100644
index 000000000..5adc5d03f
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/dkms.conf
@@ -0,0 +1,6 @@
+BUILT_MODULE_NAME=vboxdrv
+DEST_MODULE_LOCATION=/kernel/misc
+PACKAGE_NAME=vboxdrv
+PACKAGE_VERSION=_VERSION_
+AUTOINSTALL=yes
+POST_BUILD="do_Module.symvers vboxdrv save $dkms_tree/$module/$module_version/build/Module.symvers"
diff --git a/src/VBox/HostDrivers/Support/linux/files_vboxdrv b/src/VBox/HostDrivers/Support/linux/files_vboxdrv
new file mode 100644
index 000000000..bca75a850
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/files_vboxdrv
@@ -0,0 +1,129 @@
+#!/bin/sh
+#
+# Shared file between Makefile.kmk and export_modules
+#
+# Copyright (C) 2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+FILES_VBOXDRV_NOBIN=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/param.h=>include/VBox/param.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c=>linux/SUPDrv-linux.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrv.c=>SUPDrv.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIDC.h=>SUPDrvIDC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIOC.h=>SUPDrvIOC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvInternal.h=>SUPDrvInternal.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/alloc/heapsimple.cpp=>alloc/heapsimple.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp=>common/err/RTErrConvertFromErrno.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/log.cpp=>common/log/log.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logellipsis.cpp=>common/log/logellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrel.cpp=>common/log/logrel.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrelellipsis.cpp=>common/log/logrelellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logcom.cpp=>common/log/logcom.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logformat.cpp=>common/log/logformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divdi3.c=>math/gcc/divdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/moddi3.c=>math/gcc/moddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/qdivrem.c=>math/gcc/qdivrem.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/quad.h=>math/gcc/quad.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformat.cpp=>common/string/strformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatrt.cpp=>common/string/strformatrt.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformattype.cpp=>common/string/strformattype.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf.cpp=>common/string/strprintf.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strtonum.cpp=>common/string/strtonum.c \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/initterm.h=>include/internal/initterm.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/magics.h=>include/internal/magics.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/memobj.h=>include/internal/memobj.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/string.h=>include/internal/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/thread.h=>include/internal/thread.h \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp=>generic/RTAssertShouldPanic-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp=>generic/RTLogWriteStdErr-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp=>generic/RTLogWriteStdOut-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp=>generic/RTLogWriteUser-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.cpp=>r0drv/alloc-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.h=>r0drv/alloc-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/initterm-r0drv.cpp=>r0drv/initterm-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mp-r0drv.h=>r0drv/mp-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mpnotification-r0drv.c=>r0drv/mpnotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/power-r0drv.h=>r0drv/power-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/powernotification-r0drv.c=>r0drv/powernotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c=>r0drv/linux/RTLogWriteDebugger-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c=>r0drv/linux/assert-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c=>r0drv/linux/alloc-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c=>r0drv/linux/initterm-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c=>r0drv/linux/memobj-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c=>r0drv/linux/mp-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c=>r0drv/linux/mpnotification-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c=>r0drv/linux/process-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c=>r0drv/linux/semevent-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c=>r0drv/linux/semeventmulti-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c=>r0drv/linux/semfastmutex-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c=>r0drv/linux/spinlock-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/string.h=>r0drv/linux/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c=>r0drv/linux/thread-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c=>r0drv/linux/thread2-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c=>r0drv/linux/time-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c=>r0drv/linux/timer-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/memobj-r0drv.cpp=>r0drv/memobj-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/log-vbox.cpp=>VBox/log-vbox.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/strformat-vbox.cpp=>VBox/strformat-vbox.c \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+"
+
+FILES_VBOXDRV_BIN=" \
+"
diff --git a/src/VBox/HostDrivers/Support/os2/Makefile.kup b/src/VBox/HostDrivers/Support/os2/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp
new file mode 100644
index 000000000..86fdd350c
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp
@@ -0,0 +1,425 @@
+/* $Id: SUPDrv-os2.cpp 13998 2008-11-10 12:08:56Z vboxsync $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - OS/2 specifics.
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#define __STDC_CONSTANT_MACROS
+#define __STDC_LIMIT_MACROS
+
+#include <os2ddk/bsekee.h>
+#undef RT_MAX
+
+#include "SUPDrvInternal.h"
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/spinlock.h>
+#include <iprt/process.h>
+#include <iprt/assert.h>
+#include <VBox/log.h>
+#include <iprt/param.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Device extention & session data association structure.
+ */
+static SUPDRVDEVEXT g_DevExt;
+/** Spinlock protecting g_apSessionHashTab. */
+static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
+/** Hash table */
+static PSUPDRVSESSION g_apSessionHashTab[19];
+/** Calculates the index into g_apSessionHashTab.*/
+#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
+
+__BEGIN_DECLS
+/* Defined in SUPDrvA-os2.asm */
+extern uint16_t g_offLogHead;
+extern uint16_t volatile g_offLogTail;
+extern uint16_t const g_cchLogMax;
+extern char g_szLog[];
+/* (init only:) */
+extern char g_szInitText[];
+extern uint16_t g_cchInitText;
+extern uint16_t g_cchInitTextMax;
+__END_DECLS
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+
+
+
+/**
+ * 32-bit Ring-0 initialization.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param pszArgs Pointer to the device arguments.
+ */
+DECLASM(int) VBoxDrvInit(const char *pszArgs)
+{
+ dprintf(("VBoxDrvInit: pszArgs=%s\n", pszArgs));
+
+ /*
+ * Initialize the runtime.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the device extension.
+ */
+ rc = supdrvInitDevExt(&g_DevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the session hash table.
+ */
+ rc = RTSpinlockCreate(&g_Spinlock);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Process the commandline. Later.
+ */
+ bool fVerbose = true;
+
+ /*
+ * Success
+ */
+ if (fVerbose)
+ {
+ strcpy(&g_szInitText[0],
+ "\r\n"
+ "VirtualBox.org Support Driver for OS/2 version " VBOX_VERSION_STRING "\r\n"
+ "Copyright (C) 2007 Knut St. Osmundsen\r\n"
+ "Copyright (C) 2007 Sun Microsystems, Inc.\r\n");
+ g_cchInitText = strlen(&g_szInitText[0]);
+ }
+ return VINF_SUCCESS;
+ }
+ g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxDrv.sys: RTSpinlockCreate failed, rc=%Rrc\n", rc);
+ supdrvDeleteDevExt(&g_DevExt);
+ }
+ else
+ g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxDrv.sys: supdrvInitDevExt failed, rc=%Rrc\n", rc);
+ RTR0Term();
+ }
+ else
+ g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxDrv.sys: RTR0Init failed, rc=%Rrc\n", rc);
+ return rc;
+}
+
+
+DECLASM(int) VBoxDrvOpen(uint16_t sfn)
+{
+ int rc;
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Create a new session.
+ */
+ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ pSession->sfn = sfn;
+
+ /*
+ * Insert it into the hash table.
+ */
+ unsigned iHash = SESSION_HASH(sfn);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession->pNextHash = g_apSessionHashTab[iHash];
+ g_apSessionHashTab[iHash] = pSession;
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ }
+
+ dprintf(("VBoxDrvOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
+ return rc;
+}
+
+
+DECLASM(int) VBoxDrvClose(uint16_t sfn)
+{
+ dprintf(("VBoxDrvClose: pid=%d sfn=%d\n", (int)RTProcSelf(), sfn));
+
+ /*
+ * Remove from the hash table.
+ */
+ PSUPDRVSESSION pSession;
+ const RTPROCESS Process = RTProcSelf();
+ const unsigned iHash = SESSION_HASH(sfn);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession)
+ {
+ if ( pSession->sfn == sfn
+ && pSession->Process == Process)
+ {
+ g_apSessionHashTab[iHash] = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ }
+ else
+ {
+ PSUPDRVSESSION pPrev = pSession;
+ pSession = pSession->pNextHash;
+ while (pSession)
+ {
+ if ( pSession->sfn == sfn
+ && pSession->Process == Process)
+ {
+ pPrev->pNextHash = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ break;
+ }
+
+ /* next */
+ pPrev = pSession;
+ pSession = pSession->pNextHash;
+ }
+ }
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ OSDBGPRINT(("VBoxDrvIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d sfn=%d\n", (int)Process, sfn));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Close the session.
+ */
+ supdrvCloseSession(&g_DevExt, pSession);
+ return 0;
+}
+
+
+DECLASM(int) VBoxDrvIOCtlFast(uint16_t sfn, uint8_t iFunction)
+{
+ /*
+ * Find the session.
+ */
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ const RTPROCESS Process = RTProcSelf();
+ const unsigned iHash = SESSION_HASH(sfn);
+ PSUPDRVSESSION pSession;
+
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession && pSession->Process != Process)
+ {
+ do pSession = pSession->pNextHash;
+ while ( pSession
+ && ( pSession->sfn != sfn
+ || pSession->Process != Process));
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (RT_UNLIKELY(!pSession))
+ {
+ OSDBGPRINT(("VBoxDrvIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Dispatch the fast IOCtl.
+ */
+ supdrvIOCtlFast(iFunction, 0, &g_DevExt, pSession);
+ return 0;
+}
+
+
+DECLASM(int) VBoxDrvIOCtl(uint16_t sfn, uint8_t iCat, uint8_t iFunction, void *pvParm, void *pvData, uint16_t *pcbParm, uint16_t *pcbData)
+{
+ /*
+ * Find the session.
+ */
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ const RTPROCESS Process = RTProcSelf();
+ const unsigned iHash = SESSION_HASH(sfn);
+ PSUPDRVSESSION pSession;
+
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession && pSession->Process != Process)
+ {
+ do pSession = pSession->pNextHash;
+ while ( pSession
+ && ( pSession->sfn != sfn
+ || pSession->Process != Process));
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ OSDBGPRINT(("VBoxDrvIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Verify the category and dispatch the IOCtl.
+ */
+ if (RT_LIKELY(iCat == SUP_CTL_CATEGORY))
+ {
+ dprintf(("VBoxDrvIOCtl: pSession=%p iFunction=%#x pvParm=%p pvData=%p *pcbParm=%d *pcbData=%d\n", pSession, iFunction, pvParm, pvData, *pcbParm, *pcbData));
+ Assert(pvParm);
+ Assert(!pvData);
+
+ /*
+ * Lock the header.
+ */
+ PSUPREQHDR pHdr = (PSUPREQHDR)pvParm;
+ AssertReturn(*pcbParm == sizeof(*pHdr), VERR_INVALID_PARAMETER);
+ KernVMLock_t Lock;
+ int rc = KernVMLock(VMDHL_WRITE, pHdr, *pcbParm, &Lock, (KernPageList_t *)-1, NULL);
+ AssertMsgReturn(!rc, ("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pHdr, *pcbParm, &Lock, rc), VERR_LOCK_FAILED);
+
+ /*
+ * Validate the header.
+ */
+ if (RT_LIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) == SUPREQHDR_FLAGS_MAGIC))
+ {
+ uint32_t cbReq = RT_MAX(pHdr->cbIn, pHdr->cbOut);
+ if (RT_LIKELY( pHdr->cbIn >= sizeof(*pHdr)
+ && pHdr->cbOut >= sizeof(*pHdr)
+ && cbReq <= _1M*16))
+ {
+ /*
+ * Lock the rest of the buffer if necessary.
+ */
+ if (((uintptr_t)pHdr & PAGE_OFFSET_MASK) + cbReq > PAGE_SIZE)
+ {
+ rc = KernVMUnlock(&Lock);
+ AssertMsgReturn(!rc, ("KernVMUnlock(Lock) -> %#x\n", rc), VERR_LOCK_FAILED);
+
+ rc = KernVMLock(VMDHL_WRITE, pHdr, cbReq, &Lock, (KernPageList_t *)-1, NULL);
+ AssertMsgReturn(!rc, ("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pHdr, cbReq, &Lock, rc), VERR_LOCK_FAILED);
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ rc = supdrvIOCtl(iFunction, &g_DevExt, pSession, pHdr);
+ }
+ else
+ {
+ OSDBGPRINT(("VBoxDrvIOCtl: max(%#x,%#x); iCmd=%#x\n", pHdr->cbIn, pHdr->cbOut, iFunction));
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ OSDBGPRINT(("VBoxDrvIOCtl: bad magic fFlags=%#x; iCmd=%#x\n", pHdr->fFlags, iFunction));
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * Unlock and return.
+ */
+ int rc2 = KernVMUnlock(&Lock);
+ AssertMsg(!rc2, ("rc2=%d\n", rc2)); NOREF(rc2);
+
+ dprintf2(("VBoxDrvIOCtl: returns %d\n", rc));
+ return rc;
+ }
+ return VERR_NOT_SUPPORTED;
+}
+
+
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ NOREF(pDevExt);
+ return false;
+}
+
+
+/**
+ * Callback for writing to the log buffer.
+ *
+ * @returns number of bytes written.
+ * @param pvArg Unused.
+ * @param pachChars Pointer to an array of utf-8 characters.
+ * @param cbChars Number of bytes in the character array pointed to by pachChars.
+ */
+static DECLCALLBACK(size_t) VBoxDrvLogOutput(void *pvArg, const char *pachChars, size_t cbChars)
+{
+ size_t cchWritten = 0;
+ while (cbChars-- > 0)
+ {
+ const uint16_t offLogHead = g_offLogHead;
+ const uint16_t offLogHeadNext = (offLogHead + 1) & (g_cchLogMax - 1);
+ if (offLogHeadNext == g_offLogTail)
+ break; /* no */
+ g_szLog[offLogHead] = *pachChars++;
+ g_offLogHead = offLogHeadNext;
+ cchWritten++;
+ }
+ return cchWritten;
+}
+
+
+SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+ va_list va;
+
+#if 0 //def DEBUG_bird
+ va_start(va, pszFormat);
+ RTLogComPrintfV(pszFormat, va);
+ va_end(va);
+#endif
+
+ va_start(va, pszFormat);
+ int cch = RTLogFormatV(VBoxDrvLogOutput, NULL, pszFormat, va);
+ va_end(va);
+
+ return cch;
+}
diff --git a/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.def b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.def
new file mode 100644
index 000000000..6e71395cb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.def
@@ -0,0 +1,48 @@
+;; @file
+; VBoxDrv - OS/2 definition file.
+;
+
+;
+; Copyright (C) 2007 Sun Microsystems, Inc.
+;
+; 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.
+;
+; Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+; Clara, CA 95054 USA or visit http://www.sun.com if you need
+; additional information or have any questions.
+;
+
+
+PHYSICAL DEVICE VBoxDrv
+DESCRIPTION 'VirtualBox.org Support Driver for OS/2.'
+CODE PRELOAD EXECUTEREAD
+DATA PRELOAD
+; We're using wlink.exe, so this doesn't work.
+;SEGMENTS
+; DATA16 class 'FAR_DATA'
+; DATA16_INIT class 'FAR_DATA'
+;
+; CODE16 class 'CODE'
+; CODE16_INIT class 'CODE'
+;
+; CODE32 class 'CODE'
+; TEXT32 class 'CODE'
+;
+; DATA32 class 'DATA'
+; BSS32 class 'BSS'
+
diff --git a/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm b/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm
new file mode 100644
index 000000000..4498a58df
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPDrvA-os2.asm
@@ -0,0 +1,974 @@
+; $Id: SUPDrvA-os2.asm 10729 2008-07-17 15:05:47Z vboxsync $
+;; @file
+; VBoxDrv - OS/2 assembly file, the first file in the link.
+;
+
+;
+; Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+;
+; Permission is hereby granted, free of charge, to any person
+; obtaining a copy of this software and associated documentation
+; files (the "Software"), to deal in the Software without
+; restriction, including without limitation the rights to use,
+; copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the
+; Software is furnished to do so, subject to the following
+; conditions:
+;
+; The above copyright notice and this permission notice shall be
+; included in all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+; OTHER DEALINGS IN THE SOFTWARE.
+;
+
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%define RT_INCL_16BIT_SEGMENTS
+%include "iprt/asmdefs.mac"
+
+
+;*******************************************************************************
+;* Structures and Typedefs *
+;*******************************************************************************
+;;
+; Request packet header.
+struc PKTHDR
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+endstruc
+
+
+;;
+; Init request packet - input.
+struc PKTINITIN
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .data_1 resb 1
+ .fpfnDevHlp resd 1
+ .fpszArgs resd 1
+ .data_2 resb 1
+endstruc
+
+;;
+; Init request packet - output.
+struc PKTINITOUT
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .cUnits resb 1 ; block devs only.
+ .cbCode16 resw 1
+ .cbData16 resw 1
+ .fpaBPBs resd 1 ; block devs only.
+ .data_2 resb 1
+endstruc
+
+;;
+; Open request packet.
+struc PKTOPEN
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+ .sfn resw 1
+endstruc
+
+;;
+; Close request packet.
+struc PKTCLOSE
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+ .sfn resw 1
+endstruc
+
+;;
+; IOCtl request packet.
+struc PKTIOCTL
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .cat resb 1
+ .fun resb 1
+ .pParm resd 1
+ .pData resd 1
+ .sfn resw 1
+ .cbParm resw 1
+ .cbData resw 1
+endstruc
+
+;;
+; Read/Write request packet
+struc PKTRW
+ .cb resb 1
+ .unit resb 1
+ .cmd resb 1
+ .status resw 1
+ .res1 resd 1
+ .link resd 1
+
+ .media resb 1
+ .PhysTrans resd 1
+ .cbTrans resw 1
+ .start resd 1
+ .sfn resw 1
+endstruc
+
+
+
+;;
+; The two device headers.
+segment DATA16
+
+; Some devhdr.inc stuff.
+%define DEVLEV_3 0180h
+%define DEV_30 0800h
+%define DEV_CHAR_DEV 8000h
+%define DEV_16MB 0002h
+%define DEV_IOCTL2 0001h
+
+; Some dhcalls.h stuff.
+%define DevHlp_VirtToLin 05bh
+%define DevHlp_SAVE_MESSAGE 03dh
+%define DevHlp_PhysToVirt 015h
+
+; Fast IOCtl category, also defined in SUPDrvIOC.h
+%define SUP_CTL_CATEGORY_FAST 0c1h
+
+
+;*******************************************************************************
+;* External Symbols *
+;*******************************************************************************
+extern KernThunkStackTo32
+extern KernThunkStackTo16
+extern DOS16OPEN
+extern DOS16CLOSE
+extern DOS16WRITE
+extern NAME(VBoxDrvInit)
+extern NAME(VBoxDrvOpen)
+extern NAME(VBoxDrvClose)
+extern NAME(VBoxDrvIOCtl)
+extern NAME(VBoxDrvIOCtlFast)
+
+
+;;
+; Device headers. The first one is the one we'll be opening and the
+; latter is only used for 32-bit initialization.
+GLOBALNAME g_VBoxDrvHdr1
+ dw NAME(g_VBoxDrvHdr2) wrt DATA16 ; NextHeader.off
+ dw DATA16 ; NextHeader.sel
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
+ dw NAME(VBoxDrvEP) wrt CODE16 ; StrategyEP
+ dw 0 ; InterruptEP
+ db 'vboxdrv$' ; DevName
+ dw 0 ; SDevProtCS
+ dw 0 ; SDevProtDS
+ dw 0 ; SDevRealCS
+ dw 0 ; SDevRealDS
+ dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
+
+align 4
+GLOBALNAME g_VBoxDrvHdr2
+ dd 0ffffffffh ; NextHeader (NIL)
+ dw DEVLEV_3 | DEV_30 | DEV_CHAR_DEV; SDevAtt
+ dw NAME(VBoxDrvInitEP) wrt CODE16 ; StrategyEP
+ dw 0 ; InterruptEP
+ db 'vboxdr1$' ; DevName
+ dw 0 ; SDevProtCS
+ dw 0 ; SDevProtDS
+ dw 0 ; SDevRealCS
+ dw 0 ; SDevRealDS
+ dd DEV_16MB | DEV_IOCTL2 ; SDevCaps
+
+
+;; Tristate 32-bit initialization indicator [0 = need init, -1 = init failed, 1 init succeeded].
+; Check in the open path of the primary driver. The secondary driver will
+; open the primary one during it's init and thereby trigger the 32-bit init.
+GLOBALNAME g_fInitialized
+ db 0
+
+align 4
+;; Pointer to the device helper service routine
+; This is set during the initialization of the 2nd device driver.
+GLOBALNAME g_fpfnDevHlp
+ dd 0
+
+
+;; Where we write to the log.
+GLOBALNAME g_offLogHead
+ dw 0
+;; Where we read from the log.
+GLOBALNAME g_offLogTail
+ dw 0
+;; The size of the log. (power of two!)
+%define LOG_SIZE 16384
+GLOBALNAME g_cchLogMax
+ dw LOG_SIZE
+;; The log buffer.
+GLOBALNAME g_szLog
+ times LOG_SIZE db 0
+
+
+;
+; The init data.
+;
+segment DATA16_INIT
+GLOBALNAME g_InitDataStart
+
+;; Far pointer to the device argument.
+g_fpszArgs:
+ dd 0
+
+%if 0
+;; Message table for the Save_Message device helper.
+GLOBALNAME g_MsgTab
+ dw 1178 ; MsgId - 'MSG_REPLACEMENT_STRING'.
+ dw 1 ; cMsgStrings
+ dw NAME(g_szInitText) ; MsgStrings[0]
+ dw seg NAME(g_szInitText)
+%else
+;; Far pointer to DOS16WRITE (corrected set before called).
+; Just a temporary hack to work around a wlink issue.
+GLOBALNAME g_fpfnDos16Write
+ dw DOS16WRITE
+ dw seg DOS16WRITE
+%endif
+
+;; Size of the text currently in the g_szInitText buffer.
+GLOBALNAME g_cchInitText
+ dw 0
+;; The max size of text that can fit into the g_szInitText buffer.
+GLOBALNAME g_cchInitTextMax
+ dw 512
+;; The init text buffer.
+GLOBALNAME g_szInitText
+ times 512 db 0
+
+;
+; The 16-bit code segment.
+;
+segment CODE16
+
+
+;;
+; The strategy entry point (vboxdrv$).
+;
+; ss:bx -> request packet
+; ds:si -> device header
+;
+; Can clobber any registers it likes except SP.
+;
+BEGINPROC VBoxDrvEP
+ push ebp
+ mov ebp, esp
+ push es ; bp - 2
+ push bx ; bp - 4
+ and sp, 0fffch
+
+ ;
+ ; Check for the most frequent first.
+ ;
+ cmp byte [es:bx + PKTHDR.cmd], 10h ; Generic IOCtl
+ jne near VBoxDrvEP_NotGenIOCtl
+
+
+ ;
+ ; Generic I/O Control Request.
+ ;
+VBoxDrvEP_GenIOCtl:
+
+ ; Fast IOCtl?
+ cmp byte [es:bx + PKTIOCTL.cat], SUP_CTL_CATEGORY_FAST
+ jne VBoxDrvEP_GenIOCtl_Other
+
+ ;
+ ; Fast IOCtl.
+ ; DECLASM(int) VBoxDrvIOCtlFast(uint16_t sfn, uint8_t iFunction)
+ ;
+VBoxDrvEP_GenIOCtl_Fast:
+ ; function.
+ movzx edx, byte [es:bx + PKTIOCTL.fun]
+ push edx ; 04h
+
+ ; system file number.
+ movzx eax, word [es:bx + PKTIOCTL.sfn]
+ push eax ; 00h
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_GenIOCtl_Fast_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code (don't cleanup the stack).
+ call NAME(VBoxDrvIOCtlFast)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_GenIOCtl_Fast_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_GenIOCtl_Fast_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+
+ ; setup output stuff.
+ xor eax, eax
+ mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+
+ mov sp, bp
+ pop ebp
+ retf
+
+ ;
+ ; Other IOCtl (slow)
+ ;
+VBoxDrvEP_GenIOCtl_Other:
+ mov eax, [es:bx + PKTIOCTL.cbParm] ; Load cbParm and cbData
+ push eax ; 1eh - in/out data size.
+ ; 1ch - in/out parameter size.
+ push edx ; 18h - pointer to data size (filled in later).
+ push ecx ; 14h - pointer to param size (filled in later).
+
+ ; pData (convert to flat 32-bit)
+ mov ax, word [es:bx + PKTIOCTL.pData + 2] ; selector
+ cmp ax, 3 ; <= 3 -> nil selector...
+ jbe .no_data
+ movzx esi, word [es:bx + PKTIOCTL.pData] ; offset
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvEP_GeneralFailure
+ jmp .finish_data
+.no_data:
+ xor eax, eax
+.finish_data:
+ push eax ; 10h
+
+ ; pParm (convert to flat 32-bit)
+ mov ax, word [es:bx + PKTIOCTL.pParm + 2] ; selector
+ cmp ax, 3 ; <= 3 -> nil selector...
+ jbe .no_parm
+ movzx esi, word [es:bx + PKTIOCTL.pParm] ; offset
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvEP_GeneralFailure
+ jmp .finish_parm
+.no_parm:
+ xor eax, eax
+.finish_parm:
+ push eax ; 0ch
+
+ ; function.
+ movzx edx, byte [es:bx + PKTIOCTL.fun]
+ push edx ; 08h
+
+ ; category.
+ movzx ecx, byte [es:bx + PKTIOCTL.cat]
+ push ecx ; 04h
+
+ ; system file number.
+ movzx eax, word [es:bx + PKTIOCTL.sfn]
+ push eax ; 00h
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_GenIOCtl_Other_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_GenIOCtl_Other_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; update in/out parameter pointers
+ lea eax, [esp + 1ch]
+ mov [esp + 14h], eax
+ lea edx, [esp + 1eh]
+ mov [esp + 18h], edx
+
+ ; call the C code (don't cleanup the stack).
+ call NAME(VBoxDrvIOCtl)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_GenIOCtl_Other_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_GenIOCtl_Other_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+
+ ; setup output stuff.
+ mov edx, esp
+ mov eax, [ss:edx + 1ch] ; output sizes.
+ mov [es:bx + PKTIOCTL.cbParm], eax ; update cbParm and cbData.
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+
+ mov sp, bp
+ pop ebp
+ retf
+
+
+ ;
+ ; Less Performance Critical Requests.
+ ;
+VBoxDrvEP_NotGenIOCtl:
+ cmp byte [es:bx + PKTHDR.cmd], 0dh ; Open
+ je VBoxDrvEP_Open
+ cmp byte [es:bx + PKTHDR.cmd], 0eh ; Close
+ je VBoxDrvEP_Close
+ cmp byte [es:bx + PKTHDR.cmd], 00h ; Init
+ je VBoxDrvEP_Init
+ cmp byte [es:bx + PKTHDR.cmd], 04h ; Read
+ je near VBoxDrvEP_Read
+ jmp near VBoxDrvEP_NotSupported
+
+
+ ;
+ ; Open Request. w/ ring-0 init.
+ ;
+VBoxDrvEP_Open:
+ cmp byte [NAME(g_fInitialized)], 1
+ jne VBoxDrvEP_OpenOther
+
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_Open_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_Open_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_Open_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvOpen)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_Open_32) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_Open_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_Open_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+ ; Initializing or failed init?
+VBoxDrvEP_OpenOther:
+ cmp byte [NAME(g_fInitialized)], 0
+ jne VBoxDrvEP_OpenFailed
+
+ mov byte [NAME(g_fInitialized)], -1
+ call NAME(VBoxDrvRing0Init)
+ cmp byte [NAME(g_fInitialized)], 1
+ je VBoxDrvEP_Open
+
+VBoxDrvEP_OpenFailed:
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Close Request.
+ ;
+VBoxDrvEP_Close:
+ ; First argument, the system file number.
+ movzx eax, word [es:bx + PKTOPEN.sfn]
+ push eax
+
+ ; go to the 32-bit code
+ ;jmp far dword NAME(VBoxDrvEP_Close_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvEP_Close_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvEP_Close_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvClose)
+
+ ; switch back the stack.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvEP_Close_32) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvEP_Close_16) wrt CODE16
+ dw CODE16
+segment CODE16
+GLOBALNAME VBoxDrvEP_Close_16
+ les bx, [bp - 4] ; Reload the packet pointer.
+ or eax, eax
+ jnz near VBoxDrvEP_GeneralFailure
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Init Request.
+ ; The other driver header will do this.
+ ;
+VBoxDrvEP_Init:
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
+ mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp near VBoxDrvEP_Done
+
+
+ ;
+ ; Read Request.
+ ; Return log data.
+ ;
+VBoxDrvEP_Read:
+ ; Any log data available?
+ xor dx, dx
+ mov ax, [NAME(g_offLogTail)]
+ cmp ax, [NAME(g_offLogHead)]
+ jz near .log_done
+
+ ; create a temporary mapping of the physical buffer. Docs claims it trashes nearly everything...
+ push ebp
+ mov cx, [es:bx + PKTRW.cbTrans]
+ push cx
+ mov ax, [es:bx + PKTRW.PhysTrans + 2]
+ mov bx, [es:bx + PKTRW.PhysTrans]
+ mov dh, 1
+ mov dl, DevHlp_PhysToVirt
+ call far [NAME(g_fpfnDevHlp)]
+ pop bx ; bx = cbTrans
+ pop ebp
+ jc near .log_phystovirt_failed
+ ; es:di -> the output buffer.
+
+ ; setup the copy operation.
+ mov ax, [NAME(g_offLogTail)]
+ xor dx, dx ; dx tracks the number of bytes copied.
+.log_loop:
+ mov cx, [NAME(g_offLogHead)]
+ cmp ax, cx
+ je .log_done
+ jb .log_loop_before
+ mov cx, LOG_SIZE
+.log_loop_before: ; cx = end offset
+ sub cx, ax ; cx = sequential bytes to copy.
+ cmp cx, bx
+ jbe .log_loop_min
+ mov cx, bx ; output buffer is smaller than available data.
+.log_loop_min:
+ mov si, NAME(g_szLog)
+ add si, ax ; ds:si -> the log buffer.
+ add dx, cx ; update output counter
+ add ax, cx ; calc new offLogTail
+ and ax, LOG_SIZE - 1
+ rep movsb ; do the copy
+ mov [NAME(g_offLogTail)], ax ; commit the read.
+ jmp .log_loop
+
+.log_done:
+ les bx, [bp - 4] ; Reload the packet pointer.
+ mov word [es:bx + PKTRW.cbTrans], dx
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ jmp near VBoxDrvEP_Done
+
+.log_phystovirt_failed:
+ les bx, [bp - 4] ; Reload the packet pointer.
+ jmp VBoxDrvEP_GeneralFailure
+
+
+ ;
+ ; Return 'unknown command' error.
+ ;
+VBoxDrvEP_NotSupported:
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ jmp VBoxDrvEP_Done
+
+ ;
+ ; Return 'general failure' error.
+ ;
+VBoxDrvEP_GeneralFailure:
+ mov word [es:bx + PKTHDR.status], 0810ch ; error, done, general failure.
+ jmp VBoxDrvEP_Done
+
+ ;
+ ; Non-optimized return path.
+ ;
+VBoxDrvEP_Done:
+ mov sp, bp
+ pop ebp
+ retf
+ENDPROC VBoxDrvEP
+
+
+;;
+; The helper device entry point.
+;
+; This is only used to do the DosOpen on the main driver so we can
+; do ring-3 init and report failures.
+;
+GLOBALNAME VBoxDrvInitEP
+ ; The only request we're servicing is the 'init' one.
+ cmp word [es:bx + PKTHDR.cmd], 0
+ je near NAME(VBoxDrvInitEPServiceInitReq)
+
+ ; Ok, it's not the init request, just fail it.
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ retf
+
+
+;
+; The 16-bit init code.
+;
+segment CODE16_INIT
+GLOBALNAME g_InitCodeStart
+
+;; The device name for DosOpen.
+g_szDeviceName:
+ db '\DEV\vboxdrv$', 0
+
+; icsdebug can't see where stuff starts otherwise. (kDevTest)
+int3
+int3
+int3
+int3
+int3
+int3
+
+;;
+; The Ring-3 init code.
+;
+BEGINPROC VBoxDrvInitEPServiceInitReq
+ push ebp
+ mov ebp, esp
+ push es ; bp - 2
+ push sp ; bp - 4
+ push -1 ; bp - 6: hfOpen
+ push 0 ; bp - 8: usAction
+ and sp, 0fffch
+
+ ; check for the init package.
+ cmp word [es:bx + PKTHDR.cmd], 0
+ jne near .not_init
+
+ ;
+ ; Copy the data out of the init packet.
+ ;
+ mov eax, [es:bx + PKTINITIN.fpfnDevHlp]
+ mov [NAME(g_fpfnDevHlp)], eax
+ mov edx, [es:bx + PKTINITIN.fpszArgs]
+ mov [g_fpszArgs], edx
+
+ ;
+ ; Open the first driver, close it, and check status.
+ ;
+
+ ; APIRET _Pascal DosOpen(PSZ pszFname, PHFILE phfOpen, PUSHORT pusAction,
+ ; ULONG ulFSize, USHORT usAttr, USHORT fsOpenFlags,
+ ; USHORT fsOpenMode, ULONG ulReserved);
+ push seg g_szDeviceName ; pszFname
+ push g_szDeviceName
+ push ss ; phfOpen
+ lea dx, [bp - 6]
+ push dx
+ push ss ; pusAction
+ lea dx, [bp - 8]
+ push dx
+ push dword 0 ; ulFSize
+ push 0 ; usAttr = FILE_NORMAL
+ push 1 ; fsOpenFlags = FILE_OPEN
+ push 00040h ; fsOpenMode = OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY
+ push dword 0 ; ulReserved
+ call far DOS16OPEN
+
+ push ax ; Quickly flush any text.
+ call NAME(VBoxDrvInitFlushText)
+ pop ax
+
+ or ax, ax
+ jnz .done_err
+
+ ; APIRET APIENTRY DosClose(HFILE hf);
+ mov cx, [bp - 6]
+ push cx
+ call far DOS16CLOSE
+ or ax, ax
+ jnz .done_err ; This can't happen (I hope).
+
+ ;
+ ; Ok, we're good.
+ ;
+ mov word [es:bx + PKTHDR.status], 00100h ; done, ok.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], NAME(g_InitCodeStart) wrt CODE16
+ mov word [es:bx + PKTINITOUT.cbData16], NAME(g_InitDataStart) wrt DATA16
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp .done
+
+ ;
+ ; Init failure.
+ ;
+.done_err:
+ mov word [es:bx + PKTHDR.status], 0810fh ; error, done, init failed.
+ mov byte [es:bx + PKTINITOUT.cUnits], 0
+ mov word [es:bx + PKTINITOUT.cbCode16], 0
+ mov word [es:bx + PKTINITOUT.cbData16], 0
+ mov dword [es:bx + PKTINITOUT.fpaBPBs], 0
+ jmp .done
+
+ ;
+ ; Not init, return 'unknown command'.
+ ;
+.not_init:
+ mov word [es:bx + PKTHDR.status], 08103h ; error, done, unknown command.
+ jmp .done
+
+ ;
+ ; Request done.
+ ;
+.done:
+ mov sp, bp
+ pop ebp
+ retf
+ENDPROC VBoxDrvInitEPServiceInitReq
+
+
+;;
+; The Ring-0 init code.
+;
+BEGINPROC VBoxDrvRing0Init
+ push es
+ push esi
+ push ebp
+ mov ebp, esp
+ and sp, 0fffch
+
+ ;
+ ; Thunk the argument string pointer first.
+ ;
+ movzx esi, word [g_fpszArgs] ; offset
+ mov ax, [g_fpszArgs + 2] ; selector
+ mov dl, DevHlp_VirtToLin
+ call far [NAME(g_fpfnDevHlp)]
+ jc near VBoxDrvRing0Init_done ; eax is non-zero on failure (can't happen)
+ push eax ; 00h - pszArgs (for VBoxDrvInit).
+
+ ;
+ ; Do 16-bit init?
+ ;
+
+
+ ;
+ ; Do 32-bit init
+ ;
+ ;jmp far dword NAME(VBoxDrvRing0Init_32) wrt FLAT
+ db 066h
+ db 0eah
+ dd NAME(VBoxDrvRing0Init_32) ;wrt FLAT
+ dw TEXT32 wrt FLAT
+segment TEXT32
+GLOBALNAME VBoxDrvRing0Init_32
+
+ ; switch stack to 32-bit.
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov es, ax
+ call KernThunkStackTo32
+
+ ; call the C code.
+ call NAME(VBoxDrvInit)
+
+ ; switch back the stack and reload ds.
+ push eax
+ call KernThunkStackTo16
+ pop eax
+
+ mov dx, seg NAME(g_fInitialized)
+ mov ds, dx
+
+ ; jump back to the 16-bit code.
+ ;jmp far dword NAME(VBoxDrvRing0Init_16) wrt CODE16
+ db 066h
+ db 0eah
+ dw NAME(VBoxDrvRing0Init_16) wrt CODE16
+ dw CODE16_INIT
+segment CODE16_INIT
+GLOBALNAME VBoxDrvRing0Init_16
+
+ ; check the result and set g_fInitialized on success.
+ or eax, eax
+ jnz VBoxDrvRing0Init_done
+ mov byte [NAME(g_fInitialized)], 1
+
+VBoxDrvRing0Init_done:
+ mov sp, bp
+ pop ebp
+ pop esi
+ pop es
+ ret
+ENDPROC VBoxDrvRing0Init
+
+
+;;
+; Flush any text in the text buffer.
+;
+BEGINPROC VBoxDrvInitFlushText
+ push bp
+ mov bp, sp
+
+ ; Anything in the buffer?
+ mov ax, [NAME(g_cchInitText)]
+ or ax, ax
+ jz .done
+
+%if 1
+ ; Write it to STDOUT.
+ ; APIRET _Pascal DosWrite(HFILE hf, PVOID pvBuf, USHORT cbBuf, PUSHORT pcbBytesWritten);
+ push ax ; bp - 2 : cbBytesWritten
+ mov cx, sp
+ push 1 ; STDOUT
+ push seg NAME(g_szInitText) ; pvBuf
+ push NAME(g_szInitText)
+ push ax ; cbBuf
+ push ss ; pcbBytesWritten
+ push cx
+%if 0 ; wlink generates a non-aliased fixup here which results in 16-bit offset with the flat 32-bit selector.
+ call far DOS16WRITE
+%else
+ ; convert flat pointer to a far pointer using the tiled algorithm.
+ push ds
+ mov ax, DATA32 wrt FLAT
+ mov ds, ax
+ mov eax, g_pfnDos16Write wrt FLAT
+ movzx eax, word [eax + 2] ; High word of the flat address (in DATA32).
+ shl ax, 3
+ or ax, 0007h
+ pop ds
+ mov [NAME(g_fpfnDos16Write) + 2], ax ; Update the selector (in DATA16_INIT).
+ ; do the call
+ call far [NAME(g_fpfnDos16Write)]
+%endif
+
+%else ; alternative workaround for the wlink issue.
+ ; Use the save message devhlp.
+ push esi
+ push ebx
+ xor bx, bx
+ mov si, NAME(g_MsgTab)
+ mov dx, seg NAME(g_MsgTab)
+ mov ds, dx
+ mov dl, DevHlp_SAVE_MESSAGE
+ call far [NAME(g_fpfnDevHlp)]
+ pop ebx
+ pop esi
+%endif
+
+ ; Empty the buffer.
+ mov word [NAME(g_cchInitText)], 0
+ mov byte [NAME(g_szInitText)], 0
+
+.done:
+ mov sp, bp
+ pop bp
+ ret
+ENDPROC VBoxDrvInitFlushText
+
+
+
+;;
+; This must be present
+segment DATA32
+g_pfnDos16Write:
+ dd DOS16WRITE ; flat
+
+
diff --git a/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
new file mode 100644
index 000000000..fee169bfc
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
@@ -0,0 +1,197 @@
+/* $Id: SUPLib-os2.cpp 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - OS/2 specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define INCL_BASE
+#define INCL_ERRORS
+#include <os2.h>
+#undef RT_MAX
+
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <VBox/types.h>
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** OS/2 Device name. */
+#define DEVICE_NAME "/dev/vboxdrv$"
+
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+
+ /*
+ * Try open the device.
+ */
+ ULONG ulAction = 0;
+ HFILE hDevice = (HFILE)-1;
+ APIRET rc = DosOpen((PCSZ)DEVICE_NAME,
+ &hDevice,
+ &ulAction,
+ 0,
+ FILE_NORMAL,
+ OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
+ OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
+ NULL);
+ if (rc)
+ {
+ int vrc;
+ switch (rc)
+ {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND: vrc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: vrc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ LogRel(("Failed to open \"%s\", rc=%d, vrc=%Rrc\n", DEVICE_NAME, rc, vrc));
+ return vrc;
+ }
+
+ pThis->hDevice = (RTFILE)hDevice;
+ return VINF_SUCCESS;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Check if we're initited at all.
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ APIRET rc = DosClose((HFILE)pThis->hDevice);
+ AssertMsg(rc == NO_ERROR, ("%d\n", rc)); NOREF(rc);
+ pThis->hDevice = NIL_RTFILE;
+ }
+
+ return 0;
+}
+
+
+int suplibOsInstall(void)
+{
+ /** @remark OS/2: Not supported */
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int suplibOsUninstall(void)
+{
+ /** @remark OS/2: Not supported */
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ ULONG cbReturned = sizeof(SUPREQHDR);
+ int rc = DosDevIOCtl((HFILE)pThis->hDevice, SUP_CTL_CATEGORY, uFunction,
+ pvReq, cbReturned, &cbReturned,
+ NULL, 0, NULL);
+ if (RT_LIKELY(rc == NO_ERROR))
+ return VINF_SUCCESS;
+ return RTErrConvertFromOS2(rc);
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ NOREF(idCpu);
+ int32_t rcRet = VERR_INTERNAL_ERROR;
+ int rc = DosDevIOCtl((HFILE)pThis->hDevice, SUP_CTL_CATEGORY_FAST, uFunction,
+ NULL, 0, NULL,
+ NULL, 0, NULL);
+ if (RT_LIKELY(rc == NO_ERROR))
+ rc = rcRet;
+ else
+ rc = RTErrConvertFromOS2(rc);
+ return rc;
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ NOREF(pThis);
+ *ppvPages = NULL;
+ int rc = DosAllocMem(ppvPages, cPages << PAGE_SHIFT, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_ANY);
+ if (rc == ERROR_INVALID_PARAMETER)
+ rc = DosAllocMem(ppvPages, cPages << PAGE_SHIFT, PAG_READ | PAG_WRITE | PAG_EXECUTE | PAG_COMMIT | OBJ_ANY);
+ if (!rc)
+ rc = VINF_SUCCESS;
+ else
+ rc = RTErrConvertFromOS2(rc);
+ return rc;
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
+{
+ NOREF(pThis);
+ if (pvPages)
+ {
+ int rc = DosFreeMem(pvPages);
+ Assert(!rc); NOREF(rc);
+ }
+ return VINF_SUCCESS;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/os2/SUPR0IdcClient-os2.c b/src/VBox/HostDrivers/Support/os2/SUPR0IdcClient-os2.c
new file mode 100644
index 000000000..ef05452ec
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/os2/SUPR0IdcClient-os2.c
@@ -0,0 +1,54 @@
+/* $Id: SUPR0IdcClient-os2.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, OS/2 Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ return VERR_NOT_SUPPORTED;
+}
+
diff --git a/src/VBox/HostDrivers/Support/solaris/Makefile.kup b/src/VBox/HostDrivers/Support/solaris/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c
new file mode 100644
index 000000000..fc3e580fc
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c
@@ -0,0 +1,889 @@
+/* $Id: SUPDrv-solaris.c 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Solaris specifics.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/file.h>
+#include <sys/priv_names.h>
+#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
+
+#include "../SUPDrvInternal.h"
+#include <VBox/log.h>
+#include <VBox/version.h>
+#include <iprt/semaphore.h>
+#include <iprt/spinlock.h>
+#include <iprt/mp.h>
+#include <iprt/process.h>
+#include <iprt/thread.h>
+#include <iprt/initterm.h>
+#include <iprt/alloc.h>
+#include <iprt/string.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** @todo this quoting macros probably should be moved to a common place.
+ * The indirection is for expanding macros passed to the first macro. */
+#define VBOXSOLQUOTE2(x) #x
+#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
+/** The module name. */
+#define DEVICE_NAME "vboxdrv"
+/** The module description as seen in 'modinfo'. */
+#define DEVICE_DESC "VirtualBox HostDrv"
+/** Maximum number of driver instances. */
+#define DEVICE_MAXINSTANCES 16
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
+static int VBoxDrvSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
+static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
+static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
+static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal);
+
+static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd);
+static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd);
+
+static int VBoxSupDrvErr2SolarisErr(int rc);
+static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int Cmd, int Mode, intptr_t pArgs);
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * cb_ops: for drivers that support char/block entry points
+ */
+static struct cb_ops g_VBoxDrvSolarisCbOps =
+{
+ VBoxDrvSolarisOpen,
+ VBoxDrvSolarisClose,
+ nodev, /* b strategy */
+ nodev, /* b dump */
+ nodev, /* b print */
+ VBoxDrvSolarisRead,
+ VBoxDrvSolarisWrite,
+ VBoxDrvSolarisIOCtl,
+ nodev, /* c devmap */
+ nodev, /* c mmap */
+ nodev, /* c segmap */
+ nochpoll, /* c poll */
+ ddi_prop_op, /* property ops */
+ NULL, /* streamtab */
+ D_NEW | D_MP, /* compat. flag */
+ CB_REV /* revision */
+};
+
+/**
+ * dev_ops: for driver device operations
+ */
+static struct dev_ops g_VBoxDrvSolarisDevOps =
+{
+ DEVO_REV, /* driver build revision */
+ 0, /* ref count */
+ nulldev, /* get info */
+ nulldev, /* identify */
+ nulldev, /* probe */
+ VBoxDrvSolarisAttach,
+ VBoxDrvSolarisDetach,
+ nodev, /* reset */
+ &g_VBoxDrvSolarisCbOps,
+ (struct bus_ops *)0,
+ nodev /* power */
+};
+
+/**
+ * modldrv: export driver specifics to the kernel
+ */
+static struct modldrv g_VBoxDrvSolarisModule =
+{
+ &mod_driverops, /* extern from kernel */
+ DEVICE_DESC " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
+ &g_VBoxDrvSolarisDevOps
+};
+
+/**
+ * modlinkage: export install/remove/info to the kernel
+ */
+static struct modlinkage g_VBoxDrvSolarisModLinkage =
+{
+ MODREV_1, /* loadable module system revision */
+ &g_VBoxDrvSolarisModule,
+ NULL /* terminate array of linkage structures */
+};
+
+#ifndef USE_SESSION_HASH
+/**
+ * State info for each open file handle.
+ */
+typedef struct
+{
+ /**< Pointer to the session data. */
+ PSUPDRVSESSION pSession;
+} vbox_devstate_t;
+#else
+/** State info. for each driver instance. */
+typedef struct
+{
+ dev_info_t *pDip; /* Device handle */
+} vbox_devstate_t;
+#endif
+
+/** Opaque pointer to list of state */
+static void *g_pVBoxDrvSolarisState;
+
+/** Device extention & session data association structure */
+static SUPDRVDEVEXT g_DevExt;
+
+/* GCC C++ hack. */
+unsigned __gxx_personality_v0 = 0xcccccccc;
+
+/** Hash table */
+static PSUPDRVSESSION g_apSessionHashTab[19];
+/** Spinlock protecting g_apSessionHashTab. */
+static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
+/** Calculates bucket index into g_apSessionHashTab.*/
+#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
+
+/**
+ * Kernel entry points
+ */
+int _init(void)
+{
+ LogFlow((DEVICE_NAME ":_init\n"));
+
+ /*
+ * Prevent module autounloading.
+ */
+ modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
+ if (pModCtl)
+ pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
+ else
+ LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
+
+ /*
+ * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the device extension
+ */
+ rc = supdrvInitDevExt(&g_DevExt);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the session hash table.
+ */
+ memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
+ rc = RTSpinlockCreate(&g_Spinlock);
+ if (RT_SUCCESS(rc))
+ {
+ int rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
+ if (!rc)
+ {
+ rc = mod_install(&g_VBoxDrvSolarisModLinkage);
+ if (!rc)
+ return 0; /* success */
+
+ ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
+ LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
+
+ RTSpinlockDestroy(g_Spinlock);
+ g_Spinlock = NIL_RTSPINLOCK;
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
+ supdrvDeleteDevExt(&g_DevExt);
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
+ RTR0Term();
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: failed to init R0Drv\n"));
+ memset(&g_DevExt, 0, sizeof(g_DevExt));
+
+ return -1;
+}
+
+
+int _fini(void)
+{
+ LogFlow((DEVICE_NAME ":_fini\n"));
+
+ /*
+ * Undo the work we did at start (in the reverse order).
+ */
+ int rc = mod_remove(&g_VBoxDrvSolarisModLinkage);
+ if (rc != 0)
+ return rc;
+
+ supdrvDeleteDevExt(&g_DevExt);
+
+ rc = RTSpinlockDestroy(g_Spinlock);
+ AssertRC(rc);
+ g_Spinlock = NIL_RTSPINLOCK;
+
+ RTR0Term();
+
+ memset(&g_DevExt, 0, sizeof(g_DevExt));
+
+ ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
+ return 0;
+}
+
+
+int _info(struct modinfo *pModInfo)
+{
+ LogFlow((DEVICE_NAME ":_info\n"));
+ int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo);
+ return e;
+}
+
+
+/**
+ * Attach entry point, to attach a device to the system or resume it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (attach/resume).
+ *
+ * @return corresponding solaris error code.
+ */
+static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
+{
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisAttach\n"));
+
+ switch (enmCmd)
+ {
+ case DDI_ATTACH:
+ {
+ int rc;
+ int instance = ddi_get_instance(pDip);
+#ifdef USE_SESSION_HASH
+ vbox_devstate_t *pState;
+
+ if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: state alloc failed\n"));
+ return DDI_FAILURE;
+ }
+
+ pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
+#endif
+
+ /*
+ * Register ourselves as a character device, pseudo-driver
+ */
+#ifdef VBOX_WITH_HARDENING
+ rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
+ 0, NULL, NULL, 0600);
+#else
+ rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
+ 0, "none", "none", 0666);
+#endif
+ if (rc == DDI_SUCCESS)
+ {
+#ifdef USE_SESSION_HASH
+ pState->pDip = pDip;
+#endif
+ ddi_report_dev(pDip);
+ return DDI_SUCCESS;
+ }
+
+ return DDI_FAILURE;
+ }
+
+ case DDI_RESUME:
+ {
+ RTSemFastMutexRequest(g_DevExt.mtxGip);
+ if (g_DevExt.pGipTimer)
+ RTTimerStart(g_DevExt.pGipTimer, 0);
+
+ RTSemFastMutexRelease(g_DevExt.mtxGip);
+ return DDI_SUCCESS;
+ }
+
+ default:
+ return DDI_FAILURE;
+ }
+
+ return DDI_FAILURE;
+}
+
+
+/**
+ * Detach entry point, to detach a device to the system or suspend it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (detach/suspend).
+ *
+ * @return corresponding solaris error code.
+ */
+static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
+{
+ int rc = VINF_SUCCESS;
+
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisDetach\n"));
+ switch (enmCmd)
+ {
+ case DDI_DETACH:
+ {
+ int instance = ddi_get_instance(pDip);
+#ifndef USE_SESSION_HASH
+ ddi_remove_minor_node(pDip, NULL);
+#else
+ vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
+ ddi_remove_minor_node(pDip, NULL);
+ ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
+#endif
+ return DDI_SUCCESS;
+ }
+
+ case DDI_SUSPEND:
+ {
+ RTSemFastMutexRequest(g_DevExt.mtxGip);
+ if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0)
+ RTTimerStop(g_DevExt.pGipTimer);
+
+ RTSemFastMutexRelease(g_DevExt.mtxGip);
+ return DDI_SUCCESS;
+ }
+
+ default:
+ return DDI_FAILURE;
+ }
+}
+
+
+
+/**
+ * User context entry points
+ */
+static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
+{
+ int rc;
+ PSUPDRVSESSION pSession;
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));
+
+#ifndef USE_SESSION_HASH
+ /*
+ * Locate a new device open instance.
+ *
+ * For each open call we'll allocate an item in the soft state of the device.
+ * The item index is stored in the dev_t. I hope this is ok...
+ */
+ vbox_devstate_t *pState = NULL;
+ unsigned iOpenInstance;
+ for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
+ {
+ if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
+ && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
+ {
+ pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
+ break;
+ }
+ }
+ if (!pState)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: too many open instances.\n"));
+ return ENXIO;
+ }
+
+ /*
+ * Create a new session.
+ */
+ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ pSession->Uid = crgetruid(pCred);
+ pSession->Gid = crgetrgid(pCred);
+
+ pState->pSession = pSession;
+ *pDev = makedevice(getmajor(*pDev), iOpenInstance);
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
+ *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
+ return 0;
+ }
+
+ /* failed - clean up */
+ ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
+
+#else
+ /*
+ * Create a new session.
+ * Sessions in Solaris driver are mostly useless. It's however needed
+ * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
+ */
+ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
+ if (RT_SUCCESS(rc))
+ {
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ unsigned iHash;
+
+ pSession->Uid = crgetruid(pCred);
+ pSession->Gid = crgetrgid(pCred);
+
+ /*
+ * Insert it into the hash table.
+ */
+ iHash = SESSION_HASH(pSession->Process);
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession->pNextHash = g_apSessionHashTab[iHash];
+ g_apSessionHashTab[iHash] = pSession;
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen success\n"));
+ }
+
+ int instance;
+ for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
+ {
+ vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
+ if (pState)
+ break;
+ }
+
+ if (instance >= DEVICE_MAXINSTANCES)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: All instances exhausted\n"));
+ return ENXIO;
+ }
+
+ *pDev = makedevice(getmajor(*pDev), instance);
+
+ return VBoxSupDrvErr2SolarisErr(rc);
+#endif
+}
+
+
+static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
+{
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x\n", Dev));
+
+#ifndef USE_SESSION_HASH
+ /*
+ * Get the session and free the soft state item.
+ */
+ vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
+ if (!pState)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
+ return EFAULT;
+ }
+
+ PSUPDRVSESSION pSession = pState->pSession;
+ pState->pSession = NULL;
+ ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
+
+ if (!pSession)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
+ return EFAULT;
+ }
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
+ Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
+
+#else
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ const RTPROCESS Process = RTProcSelf();
+ const unsigned iHash = SESSION_HASH(Process);
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Remove from the hash table.
+ */
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ g_apSessionHashTab[iHash] = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ }
+ else
+ {
+ PSUPDRVSESSION pPrev = pSession;
+ pSession = pSession->pNextHash;
+ while (pSession)
+ {
+ if (pSession->Process == Process)
+ {
+ pPrev->pNextHash = pSession->pNextHash;
+ pSession->pNextHash = NULL;
+ break;
+ }
+
+ /* next */
+ pPrev = pSession;
+ pSession = pSession->pNextHash;
+ }
+ }
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
+ (int)Process));
+ return EFAULT;
+ }
+#endif
+
+ /*
+ * Close the session.
+ */
+ supdrvCloseSession(&g_DevExt, pSession);
+ return 0;
+}
+
+
+static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
+{
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisRead"));
+ return 0;
+}
+
+
+static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
+{
+ LogFlow((DEVICE_NAME ":VBoxDrvSolarisWrite"));
+ return 0;
+}
+
+
+/**
+ * Driver ioctl, an alternate entry point for this character driver.
+ *
+ * @param Dev Device number
+ * @param Cmd Operation identifier
+ * @param pArg Arguments from user to driver
+ * @param Mode Information bitfield (read/write, address space etc.)
+ * @param pCred User credentials
+ * @param pVal Return value for calling process.
+ *
+ * @return corresponding solaris error code.
+ */
+static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
+{
+#ifndef USE_SESSION_HASH
+ /*
+ * Get the session from the soft state item.
+ */
+ vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
+ if (!pState)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
+ return EINVAL;
+ }
+
+ PSUPDRVSESSION pSession = pState->pSession;
+ if (!pSession)
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
+ return DDI_SUCCESS;
+ }
+#else
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ const RTPROCESS Process = RTProcSelf();
+ const unsigned iHash = SESSION_HASH(Process);
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Find the session.
+ */
+ RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
+ pSession = g_apSessionHashTab[iHash];
+ if (pSession && pSession->Process != Process)
+ {
+ do pSession = pSession->pNextHash;
+ while (pSession && pSession->Process != Process);
+ }
+ RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
+ if (!pSession)
+ {
+ LogRel((DEVICE_NAME ":VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
+ (int)Process, Cmd));
+ return EINVAL;
+ }
+#endif
+
+ /*
+ * Deal with the two high-speed IOCtl that takes it's arguments from
+ * the session and iCmd, and only returns a VBox status code.
+ */
+ if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || Cmd == SUP_IOCTL_FAST_DO_NOP)
+ {
+ *pVal = supdrvIOCtlFast(Cmd, pArgs, &g_DevExt, pSession);
+ return 0;
+ }
+
+ return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
+}
+
+
+/** @def IOCPARM_LEN
+ * Gets the length from the ioctl number.
+ * This is normally defined by sys/ioccom.h on BSD systems...
+ */
+#ifndef IOCPARM_LEN
+# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
+#endif
+
+
+/**
+ * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
+ *
+ * @returns Solaris errno.
+ *
+ * @param pSession The session.
+ * @param Cmd The IOCtl command.
+ * @param Mode Information bitfield (for specifying ownership of data)
+ * @param iArg User space address of the request buffer.
+ */
+static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
+{
+ int rc;
+ uint32_t cbBuf = 0;
+ SUPREQHDR Hdr;
+ PSUPREQHDR pHdr;
+
+
+ /*
+ * Read the header.
+ */
+ if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(Hdr)))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(Hdr)));
+ return EINVAL;
+ }
+ rc = ddi_copyin((void *)iArg, &Hdr, sizeof(Hdr), Mode);
+ if (RT_UNLIKELY(rc))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
+ return EFAULT;
+ }
+ if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
+ return EINVAL;
+ }
+ cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
+ if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
+ || Hdr.cbOut < sizeof(Hdr)
+ || cbBuf > _1M*16))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", Hdr.cbIn, Hdr.cbOut, iCmd));
+ return EINVAL;
+ }
+
+ /*
+ * Buffer the request.
+ */
+ pHdr = RTMemTmpAlloc(cbBuf);
+ if (RT_UNLIKELY(!pHdr))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
+ return ENOMEM;
+ }
+ rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
+ if (RT_UNLIKELY(rc))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, Hdr.cbIn, iCmd, rc));
+ RTMemFree(pHdr);
+ return EFAULT;
+ }
+
+ /*
+ * Process the IOCtl.
+ */
+ rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
+
+ /*
+ * Copy ioctl data and output buffer back to user space.
+ */
+ if (RT_LIKELY(!rc))
+ {
+ uint32_t cbOut = pHdr->cbOut;
+ if (RT_UNLIKELY(cbOut > cbBuf))
+ {
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
+ cbOut = cbBuf;
+ }
+ rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
+ if (RT_UNLIKELY(rc != 0))
+ {
+ /* this is really bad */
+ LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
+ rc = EFAULT;
+ }
+ }
+ else
+ rc = EINVAL;
+
+ RTMemTmpFree(pHdr);
+ return rc;
+}
+
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code, see supdrvIDC.
+ * @param iReq The request code.
+ * @param pReq The request.
+ */
+int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Some quick validations.
+ */
+ if (RT_UNLIKELY(!VALID_PTR(pReq)))
+ return VERR_INVALID_POINTER;
+
+ pSession = pReq->pSession;
+ if (pSession)
+ {
+ if (RT_UNLIKELY(!VALID_PTR(pSession)))
+ return VERR_INVALID_PARAMETER;
+ if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
+ return VERR_INVALID_PARAMETER;
+ }
+ else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Do the job.
+ */
+ return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
+}
+
+
+/**
+ * Converts an supdrv error code to a solaris error code.
+ *
+ * @returns corresponding solaris error code.
+ * @param rc supdrv error code (SUPDRV_ERR_* defines).
+ */
+static int VBoxSupDrvErr2SolarisErr(int rc)
+{
+ switch (rc)
+ {
+ case 0: return 0;
+ case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
+ case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
+ case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
+ case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
+ case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
+ case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
+ case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
+ case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
+ case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
+ }
+
+ return EPERM;
+}
+
+
+/**
+ * Initializes any OS specific object creator fields.
+ */
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+/**
+ * Checks if the session can access the object.
+ *
+ * @returns true if a decision has been made.
+ * @returns false if the default access policy should be applied.
+ *
+ * @param pObj The object in question.
+ * @param pSession The session wanting to access the object.
+ * @param pszObjName The object name, can be NULL.
+ * @param prc Where to store the result when returning true.
+ */
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ return false;
+}
+
+
+RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+ va_list args;
+ char szMsg[512];
+
+ va_start(args, pszFormat);
+ RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
+ va_end(args);
+
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ cmn_err(CE_CONT, "%s", szMsg);
+ return 0;
+}
+
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
new file mode 100644
index 000000000..b4dbdd82f
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
@@ -0,0 +1,190 @@
+/* $Id: SUPLib-solaris.cpp 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Solaris specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <VBox/types.h>
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** Solaris device link. */
+#define DEVICE_NAME "/dev/vboxdrv"
+
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+
+
+ /*
+ * Try to open the device.
+ */
+ int hDevice = open(DEVICE_NAME, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ int rc;
+ switch (errno)
+ {
+ case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
+ case EPERM:
+ case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
+ case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", DEVICE_NAME, errno, rc));
+ return rc;
+ }
+
+ /*
+ * Mark the file handle close on exec.
+ */
+ if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) != 0)
+ {
+#ifdef IN_SUP_HARDENED_R3
+ int rc = VERR_INTERNAL_ERROR;
+#else
+ int err = errno;
+ int rc = RTErrConvertFromErrno(err);
+ LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d (%Rrc)\n", err, rc));
+#endif
+ close(hDevice);
+ return rc;
+ }
+
+ pThis->hDevice = hDevice;
+ return VINF_SUCCESS;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Check if we're initialized
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ if (close(pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = NIL_RTFILE;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsInstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+int suplibOsUninstall(void)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
+ return VINF_SUCCESS;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ int rc = ioctl(pThis->hDevice, uFunction, idCpu);
+ if (rc == -1)
+ rc = errno;
+ return rc;
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ NOREF(pThis);
+ *ppvPages = mmap(NULL, cPages * PAGE_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (*ppvPages != (void *)-1)
+ return VINF_SUCCESS;
+ return RTErrConvertFromErrno(errno);
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages)
+{
+ NOREF(pThis);
+ munmap(pvPages, cPages * PAGE_SIZE);
+ return VINF_SUCCESS;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c b/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c
new file mode 100644
index 000000000..f6dd151e0
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c
@@ -0,0 +1,59 @@
+/* $Id: SUPR0IdcClient-solaris.c 10258 2008-07-04 23:31:26Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Solaris Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc = SUPDrvSolarisIDC(iReq, pReq);
+ if (RT_SUCCESS(rc))
+ rc = pReq->rc;
+
+ NOREF(pHandle);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/solaris/mod.sh b/src/VBox/HostDrivers/Support/solaris/mod.sh
new file mode 100755
index 000000000..182185a29
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/mod.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+set -x
+#
+# Figure out the environment and locations.
+#
+
+# Sudo isn't native solaris, but it's very convenient...
+if test -z "$SUDO" && test "`whoami`" != "root"; then
+ SUDO=sudo
+fi
+
+script_dir=`dirname "$0"`
+# src/VBox/HostDrivers/solaris/ residence:
+script_dir=`cd "$script_dir/../../../../.." ; /bin/pwd`
+## root residence:
+#script_dir=`cd "$script_dir" ; /bin/pwd`
+
+set -e
+if test -z "$BUILD_TARGET"; then
+ export BUILD_TARGET=solaris
+fi
+if test -z "$BUILD_TARGET_ARCH"; then
+ export BUILD_TARGET_ARCH=x86
+fi
+if test -z "$BUILD_TYPE"; then
+ export BUILD_TYPE=debug
+fi
+
+DIR=$script_dir/out/$BUILD_TARGET.$BUILD_TARGET_ARCH/$BUILD_TYPE/bin/
+
+VBOXDRV_CONF_DIR=/platform/i86pc/kernel/drv
+if test "$BUILD_TARGET_ARCH" = "amd64"; then
+ VBOXDRV_DIR=$VBOXDRV_CONF_DIR/amd64
+else
+ VBOXDRV_DIR=$VBOXDRV_CONF_DIR
+fi
+
+#
+# Do the job.
+#
+$SUDO cp $DIR/vboxdrv $VBOXDRV_DIR/vboxdrv
+$SUDO cp $script_dir/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf $VBOXDRV_CONF_DIR/vboxdrv.conf
+old_id=`/usr/sbin/modinfo | /usr/xpg4/bin/grep vbox | cut -f 1 -d ' ' | sort -n -r `
+if test -n "$old_id"; then
+ echo "* unloading $old_id..."
+ sync
+ sync
+ $SUDO /usr/sbin/modunload -i $old_id
+#else
+# echo "* If it fails below, run: $SUDO add_drv -m'* 0666 root sys' vboxdrv"
+fi
+$SUDO /usr/sbin/rem_drv vboxdrv || echo "* ignored rem_drv failure..."
+$SUDO /usr/sbin/add_drv vboxdrv
+
+if /usr/xpg4/bin/grep -q vboxdrv /etc/devlink.tab; then
+ echo "* vboxdrv already present in /etc/devlink.tab"
+else
+ echo "* Adding vboxdrv to /etc/devlink.tab"
+ $SUDO rm -f /tmp/devlink.tab.vboxdrv
+ echo "" > /tmp/devlink.tab.vboxdrv
+ echo '# vbox' >> /tmp/devlink.tab.vboxdrv
+ echo 'type=ddi_pseudo;name=vboxdrv \D' >> /tmp/devlink.tab.vboxdrv
+ $SUDO /bin/sh -c 'cat /tmp/devlink.tab.vboxdrv >> /etc/devlink.tab'
+fi
+
+echo "* loading vboxdrv..."
+sync
+sync
+$SUDO /usr/sbin/modload $VBOXDRV_DIR/vboxdrv
+/usr/sbin/modinfo | /usr/xpg4/bin/grep vboxdrv
+echo "* dmesg:"
+dmesg | tail -20
+if test ! -h /dev/vboxdrv; then
+ $SUDO /usr/sbin/devfsadm -i vboxdrv
+fi
+ls -laL /dev/vboxdrv
diff --git a/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf b/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf
new file mode 100644
index 000000000..4b7d53d20
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf
@@ -0,0 +1,25 @@
+#
+# Sun xVM VirtualBox
+# OpenSolaris Host Driver Configuration
+#
+# Copyright (C) 2007-2008 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+# This needs to go into /platform/i86pc/kernel/drv,
+# while the 64-bit driver object goes into the amd64
+# subdirectory (32-bit drivers goes into the same
+# directory). After copying execute add_drv vboxdrv.
+#
+name="vboxdrv" parent="pseudo" instance=0;
diff --git a/src/VBox/HostDrivers/Support/testcase/Makefile.kmk b/src/VBox/HostDrivers/Support/testcase/Makefile.kmk
new file mode 100644
index 000000000..c755f723c
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/Makefile.kmk
@@ -0,0 +1,83 @@
+# $Id: Makefile.kmk 14515 2008-11-24 12:33:00Z vboxsync $
+## @file
+# Sub-Makefile for the SUPLib testcases.
+#
+
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SUB_DEPTH = ../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+PROGRAMS += \
+ SUPInstall \
+ SUPUninstall
+ifdef VBOX_WITH_TESTCASES
+PROGRAMS += \
+ tstPage \
+ tstContiguous \
+ tstInit \
+ tstInt \
+ tstLow \
+ tstPin \
+ tstGIP-2 \
+ tstGetPagingMode
+endif # VBOX_WITH_TESTCASES
+
+SUPInstall_TEMPLATE = VBOXR3EXE
+SUPInstall_SOURCES = SUPInstall.cpp
+SUPInstall_LIBS = $(LIB_RUNTIME)
+
+SUPUninstall_TEMPLATE = VBOXR3EXE
+SUPUninstall_SOURCES = SUPUninstall.cpp
+SUPUninstall_LIBS = $(LIB_RUNTIME)
+
+tstInt_TEMPLATE = VBOXR3EXE
+tstInt_SOURCES = tstInt.cpp
+tstInt_LIBS = $(LIB_RUNTIME)
+
+tstContiguous_TEMPLATE= VBOXR3TSTEXE
+tstContiguous_SOURCES = tstContiguous.cpp
+
+tstInit_TEMPLATE = VBOXR3TSTEXE
+tstInit_SOURCES = tstInit.cpp
+
+tstLow_TEMPLATE = VBOXR3TSTEXE
+tstLow_SOURCES = tstLow.cpp
+
+tstPin_TEMPLATE = VBOXR3TSTEXE
+tstPin_SOURCES = tstPin.cpp
+
+tstPage_TEMPLATE = VBOXR3TSTEXE
+tstPage_SOURCES = tstPage.cpp
+
+tstGIP-2_TEMPLATE = VBOXR3TSTEXE
+tstGIP-2_SOURCES = tstGIP-2.cpp
+
+tstGetPagingMode_TEMPLATE = VBOXR3TSTEXE
+tstGetPagingMode_SOURCES = tstGetPagingMode.cpp
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp b/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp
new file mode 100644
index 000000000..a71280730
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp
@@ -0,0 +1,53 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Testcase for driver install
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ RTR3Init();
+ int rc = SUPInstall();
+ if (RT_SUCCESS(rc))
+ {
+ printf("installed successfully\n");
+ return 0;
+ }
+ printf("installation failed. rc=%d\n", rc);
+
+ return 1;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp b/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp
new file mode 100644
index 000000000..c52234828
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp
@@ -0,0 +1,53 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Testcase for driver uninstall
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ RTR3Init();
+ int rc = SUPUninstall();
+ if (RT_SUCCESS(rc))
+ {
+ printf("uninstalled successfully\n");
+ return 0;
+ }
+ printf("uninstallation failed. rc=%d\n", rc);
+
+ return 1;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp b/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp
new file mode 100644
index 000000000..e0bf7de3a
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp
@@ -0,0 +1,104 @@
+/* $Id: tstContiguous.cpp 13837 2008-11-05 02:54:02Z vboxsync $ */
+/** @file
+ * VBox Support Driver - Contiguous Memory Testcase (ring-3).
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+int main(int argc, char **argv)
+{
+ int rc;
+ int rcRet = 0;
+
+ RTR3Init();
+ rc = SUPR3Init(NULL);
+ RTPrintf("tstContiguous: SUPR3Init -> rc=%Rrc\n", rc);
+ rcRet += rc != 0;
+ if (!rc)
+ {
+ /*
+ * Allocate a bit of contiguous memory.
+ */
+ RTHCPHYS HCPhys;
+ void *pv = SUPContAlloc(8, &HCPhys);
+ rcRet += pv == NULL || HCPhys == 0;
+ if (pv && HCPhys)
+ {
+ memset(pv, 0xff, PAGE_SIZE * 8);
+ pv = SUPContAlloc(5, &HCPhys);
+ rcRet += pv == NULL || HCPhys == 0;
+ if (pv && HCPhys)
+ {
+ memset(pv, 0x7f, PAGE_SIZE * 5);
+ rc = SUPContFree(pv, 5);
+ rcRet += rc != 0;
+ if (rc)
+ RTPrintf("tstContiguous: SUPContFree failed! rc=%Rrc\n", rc);
+
+ void *apv[128];
+ for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
+ {
+ apv[i] = SUPContAlloc(1 + (i % 11), &HCPhys);
+ if (!apv[i])
+ {
+ RTPrintf("tstContiguous: i=%d: failed to allocate %d pages\n", i, 1 + (i % 11));
+ rcRet++;
+ }
+ }
+ for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
+ if (apv[i])
+ {
+ rc = SUPContFree(apv[i], 1 + (i % 11));
+ rcRet += rc != 0;
+ if (rc)
+ RTPrintf("tstContiguous: i=%d SUPContFree failed! rc=%Rrc\n", i, rc);
+ }
+ }
+ else
+ RTPrintf("tstContiguous: SUPContAlloc (2nd) failed!\n");
+ }
+ else
+ RTPrintf("tstContiguous: SUPContAlloc failed!\n");
+
+ rc = SUPTerm();
+ RTPrintf("tstContiguous: SUPTerm -> rc=%Rrc\n", rc);
+ rcRet += rc != 0;
+ }
+
+ return rcRet ? 1 : 0;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp b/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp
new file mode 100644
index 000000000..4bb0494e6
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp
@@ -0,0 +1,185 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Test the Global Info Page interface
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+#include <iprt/thread.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+#include <iprt/getopt.h>
+
+
+int main(int argc, char **argv)
+{
+ RTR3Init();
+
+ /*
+ * Parse args
+ */
+ static const RTOPTIONDEF g_aOptions[] =
+ {
+ { "--interations", 'i', RTGETOPT_REQ_INT32 },
+ { "--hex", 'h', RTGETOPT_REQ_NOTHING },
+ { "--decimal", 'd', RTGETOPT_REQ_NOTHING },
+ { "--spin", 's', RTGETOPT_REQ_NOTHING }
+ };
+
+ uint32_t cIterations = 40;
+ bool fHex = true;
+ bool fSpin = false;
+ int ch;
+ int iArg = 1;
+ RTOPTIONUNION ValueUnion;
+ while ((ch = RTGetOpt(argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), &iArg, &ValueUnion)))
+ {
+ switch (ch)
+ {
+ case 'i':
+ cIterations = ValueUnion.u32;
+ break;
+
+ case 'd':
+ fHex = false;
+ break;
+
+ case 'h':
+ fHex = true;
+ break;
+
+ case 's':
+ fSpin = true;
+ break;
+
+ default:
+ if (ch < 0)
+ RTPrintf("tstGIP-2: %Rrc: %s\n", ch, ValueUnion.psz);
+ else
+ RTPrintf("tstGIP-2: syntax error: %s\n", ValueUnion.psz);
+ return 1;
+ }
+ }
+ if (iArg < argc)
+ {
+ RTPrintf("tstGIP-2: syntax error: %s\n", ValueUnion.psz);
+ return 1;
+ }
+
+ /*
+ * Init
+ */
+ PSUPDRVSESSION pSession = NIL_RTR0PTR;
+ int rc = SUPR3Init(&pSession);
+ if (RT_SUCCESS(rc))
+ {
+ if (g_pSUPGlobalInfoPage)
+ {
+ RTPrintf("tstGIP-2: u32UpdateHz=%RU32 u32UpdateIntervalNS=%RU32 u64NanoTSLastUpdateHz=%RX64 u32Mode=%d (%s) u32Version=%#x\n",
+ g_pSUPGlobalInfoPage->u32UpdateHz,
+ g_pSUPGlobalInfoPage->u32UpdateIntervalNS,
+ g_pSUPGlobalInfoPage->u64NanoTSLastUpdateHz,
+ g_pSUPGlobalInfoPage->u32Mode,
+ g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC ? "sync"
+ : g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_ASYNC_TSC ? "async"
+ : "???",
+ g_pSUPGlobalInfoPage->u32Version);
+ RTPrintf(fHex
+ ? "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz TSC Interval History...\n"
+ : "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz TSC Interval History...\n");
+ static SUPGIPCPU s_aaCPUs[2][RT_ELEMENTS(g_pSUPGlobalInfoPage->aCPUs)];
+ for (uint32_t i = 0; i < cIterations; i++)
+ {
+ /* copy the data */
+ memcpy(&s_aaCPUs[i & 1][0], &g_pSUPGlobalInfoPage->aCPUs[0], sizeof(g_pSUPGlobalInfoPage->aCPUs));
+
+ /* display it & find something to spin on. */
+ uint32_t u32TransactionId = 0;
+ uint32_t volatile *pu32TransactionId = NULL;
+ for (unsigned iCpu = 0; iCpu < RT_ELEMENTS(g_pSUPGlobalInfoPage->aCPUs); iCpu++)
+ if ( g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz > 0
+ && g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz != _4G + 1)
+ {
+ PSUPGIPCPU pPrevCpu = &s_aaCPUs[!(i & 1)][iCpu];
+ PSUPGIPCPU pCpu = &s_aaCPUs[i & 1][iCpu];
+ RTPrintf(fHex
+ ? "tstGIP-2: %4d/%d: %016llx %09llx %016llx %08x %d %08x %15llu %08x %08x %08x %08x %08x %08x %08x %08x (%d)\n"
+ : "tstGIP-2: %4d/%d: %016llu %09llu %016llu %010u %d %010u %15llu %08x %08x %08x %08x %08x %08x %08x %08x (%d)\n",
+ i, iCpu,
+ pCpu->u64NanoTS,
+ i ? pCpu->u64NanoTS - pPrevCpu->u64NanoTS : 0,
+ pCpu->u64TSC,
+ pCpu->u32UpdateIntervalTSC,
+ pCpu->iTSCHistoryHead,
+ pCpu->u32TransactionId,
+ pCpu->u64CpuHz,
+ pCpu->au32TSCHistory[0],
+ pCpu->au32TSCHistory[1],
+ pCpu->au32TSCHistory[2],
+ pCpu->au32TSCHistory[3],
+ pCpu->au32TSCHistory[4],
+ pCpu->au32TSCHistory[5],
+ pCpu->au32TSCHistory[6],
+ pCpu->au32TSCHistory[7],
+ pCpu->cErrors);
+ if (!pu32TransactionId)
+ {
+ pu32TransactionId = &g_pSUPGlobalInfoPage->aCPUs[iCpu].u32TransactionId;
+ u32TransactionId = pCpu->u32TransactionId;
+ }
+ }
+
+ /* wait a bit / spin */
+ if (!fSpin)
+ RTThreadSleep(9);
+ else
+ while (u32TransactionId == *pu32TransactionId)
+ /* nop */;
+ }
+ }
+ else
+ {
+ RTPrintf("tstGIP-2: g_pSUPGlobalInfoPage is NULL\n");
+ rc = -1;
+ }
+
+ SUPTerm();
+ }
+ else
+ RTPrintf("tstGIP-2: SUPR3Init failed: %Rrc\n", rc);
+ return !!rc;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp b/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp
new file mode 100644
index 000000000..ac75110f5
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp
@@ -0,0 +1,99 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Test the interface for querying host paging mode
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+
+
+int main(int argc, char **argv)
+{
+ int rc;
+ RTR3Init();
+ rc = SUPR3Init(NULL);
+ if (RT_SUCCESS(rc))
+ {
+ SUPPAGINGMODE enmMode = SUPGetPagingMode();
+ switch (enmMode)
+ {
+ case SUPPAGINGMODE_INVALID:
+ RTPrintf("SUPPAGINGMODE_INVALID\n");
+ break;
+ case SUPPAGINGMODE_32_BIT:
+ RTPrintf("SUPPAGINGMODE_32_BIT\n");
+ break;
+ case SUPPAGINGMODE_32_BIT_GLOBAL:
+ RTPrintf("SUPPAGINGMODE_32_BIT_GLOBAL\n");
+ break;
+ case SUPPAGINGMODE_PAE:
+ RTPrintf("SUPPAGINGMODE_PAE\n");
+ break;
+ case SUPPAGINGMODE_PAE_GLOBAL:
+ RTPrintf("SUPPAGINGMODE_PAE_GLOBAL\n");
+ break;
+ case SUPPAGINGMODE_PAE_NX:
+ RTPrintf("SUPPAGINGMODE_PAE_NX\n");
+ break;
+ case SUPPAGINGMODE_PAE_GLOBAL_NX:
+ RTPrintf("SUPPAGINGMODE_PAE_GLOBAL_NX\n");
+ break;
+ case SUPPAGINGMODE_AMD64:
+ RTPrintf("SUPPAGINGMODE_AMD64\n");
+ break;
+ case SUPPAGINGMODE_AMD64_GLOBAL:
+ RTPrintf("SUPPAGINGMODE_AMD64_GLOBAL\n");
+ break;
+ case SUPPAGINGMODE_AMD64_NX:
+ RTPrintf("SUPPAGINGMODE_AMD64_NX\n");
+ break;
+ case SUPPAGINGMODE_AMD64_GLOBAL_NX:
+ RTPrintf("SUPPAGINGMODE_AMD64_GLOBAL_NX\n");
+ break;
+ default:
+ RTPrintf("Unknown mode %d\n", enmMode);
+ rc = VERR_INTERNAL_ERROR;
+ break;
+ }
+
+ int rc2 = SUPTerm();
+ RTPrintf("SUPTerm -> rc=%Rrc\n", rc2);
+ }
+ else
+ RTPrintf("SUPR3Init -> rc=%Rrc\n", rc);
+
+ return !RT_SUCCESS(rc);
+}
+
diff --git a/src/VBox/HostDrivers/Support/testcase/tstInit.cpp b/src/VBox/HostDrivers/Support/testcase/tstInit.cpp
new file mode 100644
index 000000000..f4da86ae3
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstInit.cpp
@@ -0,0 +1,55 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Tests init and term of the support library
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+
+
+int main(int argc, char **argv)
+{
+ int rc;
+ RTR3Init();
+ rc = SUPR3Init(NULL);
+ RTPrintf("tstInit: SUPR3Init -> rc=%d\n", rc);
+ if (!rc)
+ {
+ rc = SUPTerm();
+ RTPrintf("tstInit: SUPTerm -> rc=%d\n", rc);
+ }
+
+ return rc;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstInt.cpp b/src/VBox/HostDrivers/Support/testcase/tstInt.cpp
new file mode 100644
index 000000000..e519b1372
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstInt.cpp
@@ -0,0 +1,233 @@
+/** $Id: tstInt.cpp 14831 2008-11-30 10:31:16Z vboxsync $ */
+/** @file
+ * Testcase: Test the interrupt gate feature of the support library.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/vm.h>
+#include <VBox/vmm.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/alloc.h>
+#include <iprt/time.h>
+
+
+/**
+ * Makes a path to a file in the executable directory.
+ */
+static char *ExeDirFile(char *pszFile, const char *pszArgv0, const char *pszFilename)
+{
+ char *psz;
+ char *psz2;
+
+ strcpy(pszFile, pszArgv0);
+ psz = strrchr(pszFile, '/');
+ psz2 = strrchr(pszFile, '\\');
+ if (psz < psz2)
+ psz = psz2;
+ if (!psz)
+ psz = strrchr(pszFile, ':');
+ if (!psz)
+ {
+ strcpy(pszFile, "./");
+ psz = &pszFile[1];
+ }
+ strcpy(psz + 1, "VMMR0.r0");
+ return pszFile;
+}
+
+int main(int argc, char **argv)
+{
+ int rcRet = 0;
+ int i;
+ int rc;
+ int cIterations = argc > 1 ? RTStrToUInt32(argv[1]) : 32;
+ if (cIterations == 0)
+ cIterations = 64;
+
+ /*
+ * Init.
+ */
+ RTR3Init();
+ PSUPDRVSESSION pSession;
+ rc = SUPR3Init(&pSession);
+ rcRet += rc != 0;
+ RTPrintf("tstInt: SUPR3Init -> rc=%Rrc\n", rc);
+ if (!rc)
+ {
+ /*
+ * Load VMM code.
+ */
+ char szFile[RTPATH_MAX];
+ rc = SUPLoadVMM(ExeDirFile(szFile, argv[0], "VMMR0.r0"));
+ if (!rc)
+ {
+ /*
+ * Create a fake 'VM'.
+ */
+ PVMR0 pVMR0 = NIL_RTR0PTR;
+ PVM pVM = NULL;
+ const unsigned cPages = RT_ALIGN_Z(sizeof(*pVM), PAGE_SIZE) >> PAGE_SHIFT;
+ PSUPPAGE paPages = (PSUPPAGE)RTMemAllocZ(cPages * sizeof(SUPPAGE));
+ if (paPages)
+ rc = SUPLowAlloc(cPages, (void **)&pVM, &pVMR0, &paPages[0]);
+ else
+ rc = VERR_NO_MEMORY;
+ if (RT_SUCCESS(rc))
+ {
+ pVM->pVMRC = 0;
+ pVM->pVMR3 = pVM;
+ pVM->pVMR0 = pVMR0;
+ pVM->paVMPagesR3 = paPages;
+ pVM->pSession = pSession;
+ pVM->enmVMState = VMSTATE_CREATED;
+
+ rc = SUPSetVMForFastIOCtl(pVMR0);
+ if (!rc)
+ {
+
+ /*
+ * Call VMM code with invalid function.
+ */
+ for (i = cIterations; i > 0; i--)
+ {
+ rc = SUPCallVMMR0(pVMR0, VMMR0_DO_SLOW_NOP, NULL);
+ if (rc != VINF_SUCCESS)
+ {
+ RTPrintf("tstInt: SUPCallVMMR0 -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
+ rcRet++;
+ break;
+ }
+ }
+ RTPrintf("tstInt: Performed SUPCallVMMR0 %d times (rc=%Rrc)\n", cIterations, rc);
+
+ /*
+ * The fast path.
+ */
+ if (rc == VINF_SUCCESS)
+ {
+ RTTimeNanoTS();
+ uint64_t StartTS = RTTimeNanoTS();
+ uint64_t StartTick = ASMReadTSC();
+ uint64_t MinTicks = UINT64_MAX;
+ for (i = 0; i < 1000000; i++)
+ {
+ uint64_t OneStartTick = ASMReadTSC();
+ rc = SUPCallVMMR0Fast(pVMR0, VMMR0_DO_NOP, 0);
+ uint64_t Ticks = ASMReadTSC() - OneStartTick;
+ if (Ticks < MinTicks)
+ MinTicks = Ticks;
+
+ if (RT_UNLIKELY(rc != VINF_SUCCESS))
+ {
+ RTPrintf("tstInt: SUPCallVMMR0Fast -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
+ rcRet++;
+ break;
+ }
+ }
+ uint64_t Ticks = ASMReadTSC() - StartTick;
+ uint64_t NanoSecs = RTTimeNanoTS() - StartTS;
+
+ RTPrintf("tstInt: SUPCallVMMR0Fast - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
+ i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);
+
+ /*
+ * The ordinary path.
+ */
+ RTTimeNanoTS();
+ StartTS = RTTimeNanoTS();
+ StartTick = ASMReadTSC();
+ MinTicks = UINT64_MAX;
+ for (i = 0; i < 1000000; i++)
+ {
+ uint64_t OneStartTick = ASMReadTSC();
+ rc = SUPCallVMMR0Ex(pVMR0, VMMR0_DO_SLOW_NOP, 0, NULL);
+ uint64_t Ticks = ASMReadTSC() - OneStartTick;
+ if (Ticks < MinTicks)
+ MinTicks = Ticks;
+
+ if (RT_UNLIKELY(rc != VINF_SUCCESS))
+ {
+ RTPrintf("tstInt: SUPCallVMMR0Ex -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
+ rcRet++;
+ break;
+ }
+ }
+ Ticks = ASMReadTSC() - StartTick;
+ NanoSecs = RTTimeNanoTS() - StartTS;
+
+ RTPrintf("tstInt: SUPCallVMMR0Ex - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
+ i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);
+ }
+ }
+ else
+ {
+ RTPrintf("tstInt: SUPSetVMForFastIOCtl failed: %Rrc\n", rc);
+ rcRet++;
+ }
+ }
+ else
+ {
+ RTPrintf("tstInt: SUPContAlloc2(%#zx,,) failed\n", sizeof(*pVM));
+ rcRet++;
+ }
+
+ /*
+ * Unload VMM.
+ */
+ rc = SUPUnloadVMM();
+ if (rc)
+ {
+ RTPrintf("tstInt: SUPUnloadVMM failed with rc=%Rrc\n", rc);
+ rcRet++;
+ }
+ }
+ else
+ {
+ RTPrintf("tstInt: SUPLoadVMM failed with rc=%Rrc\n", rc);
+ rcRet++;
+ }
+
+ /*
+ * Terminate.
+ */
+ rc = SUPTerm();
+ rcRet += rc != 0;
+ RTPrintf("tstInt: SUPTerm -> rc=%Rrc\n", rc);
+ }
+
+ return !!rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/testcase/tstLow.cpp b/src/VBox/HostDrivers/Support/testcase/tstLow.cpp
new file mode 100644
index 000000000..b15aa237d
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstLow.cpp
@@ -0,0 +1,159 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Test allocating physical memory below 4G
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ int rc;
+ int rcRet = 0;
+
+ RTR3Init();
+ RTPrintf("tstLow: TESTING...\n");
+
+ rc = SUPR3Init(NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Allocate a bit of contiguous memory.
+ */
+ SUPPAGE aPages0[128];
+ void *pvPages0 = (void *)0x77777777;
+ memset(&aPages0[0], 0x8f, sizeof(aPages0));
+ rc = SUPLowAlloc(RT_ELEMENTS(aPages0), &pvPages0, NULL, aPages0);
+ if (RT_SUCCESS(rc))
+ {
+ /* check that the pages are below 4GB and valid. */
+ for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++)
+ {
+ RTPrintf("%-4d: Phys=%RHp Reserved=%p\n", iPage, aPages0[iPage].Phys, aPages0[iPage].uReserved);
+ if (aPages0[iPage].uReserved != 0)
+ {
+ rcRet++;
+ RTPrintf("tstLow: error: aPages0[%d].uReserved=%#x expected 0!\n", iPage, aPages0[iPage].uReserved);
+ }
+ if ( aPages0[iPage].Phys >= _4G
+ || (aPages0[iPage].Phys & PAGE_OFFSET_MASK))
+ {
+ rcRet++;
+ RTPrintf("tstLow: error: aPages0[%d].Phys=%RHp!\n", iPage, aPages0[iPage].Phys);
+ }
+ }
+ if (!rcRet)
+ {
+ for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++)
+ memset((char *)pvPages0 + iPage * PAGE_SIZE, iPage, PAGE_SIZE);
+ for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++)
+ for (uint8_t *pu8 = (uint8_t *)pvPages0 + iPage * PAGE_SIZE, *pu8End = pu8 + PAGE_SIZE; pu8 < pu8End; pu8++)
+ if (*pu8 != (uint8_t)iPage)
+ {
+ RTPrintf("tstLow: error: invalid page content %02x != %02x. iPage=%p off=%#x\n",
+ *pu8, (uint8_t)iPage, iPage, (uintptr_t)pu8 & PAGE_OFFSET_MASK);
+ rcRet++;
+ }
+ }
+ SUPLowFree(pvPages0, RT_ELEMENTS(aPages0));
+ }
+ else
+ {
+ RTPrintf("SUPLowAlloc(%d,,) failed -> rc=%Rrc\n", RT_ELEMENTS(aPages0), rc);
+ rcRet++;
+ }
+
+ /*
+ * Allocate odd amounts in from 1 to 127.
+ */
+ for (unsigned cPages = 1; cPages <= 127; cPages++)
+ {
+ SUPPAGE aPages1[128];
+ void *pvPages1 = (void *)0x77777777;
+ memset(&aPages1[0], 0x8f, sizeof(aPages1));
+ rc = SUPLowAlloc(cPages, &pvPages1, NULL, aPages1);
+ if (RT_SUCCESS(rc))
+ {
+ /* check that the pages are below 4GB and valid. */
+ for (unsigned iPage = 0; iPage < cPages; iPage++)
+ {
+ RTPrintf("%-4d::%-4d: Phys=%RHp Reserved=%p\n", cPages, iPage, aPages1[iPage].Phys, aPages1[iPage].uReserved);
+ if (aPages1[iPage].uReserved != 0)
+ {
+ rcRet++;
+ RTPrintf("tstLow: error: aPages1[%d].uReserved=%#x expected 0!\n", iPage, aPages1[iPage].uReserved);
+ }
+ if ( aPages1[iPage].Phys >= _4G
+ || (aPages1[iPage].Phys & PAGE_OFFSET_MASK))
+ {
+ rcRet++;
+ RTPrintf("tstLow: error: aPages1[%d].Phys=%RHp!\n", iPage, aPages1[iPage].Phys);
+ }
+ }
+ if (!rcRet)
+ {
+ for (unsigned iPage = 0; iPage < cPages; iPage++)
+ memset((char *)pvPages1 + iPage * PAGE_SIZE, iPage, PAGE_SIZE);
+ for (unsigned iPage = 0; iPage < cPages; iPage++)
+ for (uint8_t *pu8 = (uint8_t *)pvPages1 + iPage * PAGE_SIZE, *pu8End = pu8 + PAGE_SIZE; pu8 < pu8End; pu8++)
+ if (*pu8 != (uint8_t)iPage)
+ {
+ RTPrintf("tstLow: error: invalid page content %02x != %02x. iPage=%p off=%#x\n",
+ *pu8, (uint8_t)iPage, iPage, (uintptr_t)pu8 & PAGE_OFFSET_MASK);
+ rcRet++;
+ }
+ }
+ SUPLowFree(pvPages1, cPages);
+ }
+ else
+ {
+ RTPrintf("SUPLowAlloc(%d,,) failed -> rc=%Rrc\n", cPages, rc);
+ rcRet++;
+ }
+ }
+
+ }
+ else
+ {
+ RTPrintf("SUPR3Init -> rc=%Rrc\n", rc);
+ rcRet++;
+ }
+
+
+ return rcRet;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstPage.cpp b/src/VBox/HostDrivers/Support/testcase/tstPage.cpp
new file mode 100644
index 000000000..295661fac
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstPage.cpp
@@ -0,0 +1,96 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Test the page allocation interface
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <string.h>
+
+
+int main(int argc, char **argv)
+{
+ int cErrors = 0;
+ int rc = 0;
+ RTR3InitAndSUPLib();
+ rc = SUPR3Init(NULL);
+ cErrors += rc != 0;
+ if (!rc)
+ {
+ void *pv;
+ rc = SUPPageAlloc(1, &pv);
+ cErrors += rc != 0;
+ if (!rc)
+ {
+ memset(pv, 0xff, PAGE_SIZE);
+ rc = SUPPageFree(pv, 1);
+ cErrors += rc != 0;
+ if (rc)
+ RTPrintf("tstPage: SUPPageFree() failed rc=%d\n", rc);
+ }
+ else
+ RTPrintf("tstPage: SUPPageAlloc(1,) failed rc=%d\n", rc);
+
+ /*
+ * Big chunk.
+ */
+ rc = SUPPageAlloc(1023, &pv);
+ cErrors += rc != 0;
+ if (!rc)
+ {
+ memset(pv, 0xfe, 1023 << PAGE_SHIFT);
+ rc = SUPPageFree(pv, 1023);
+ cErrors += rc != 0;
+ if (rc)
+ RTPrintf("tstPage: SUPPageFree() failed rc=%d\n", rc);
+ }
+ else
+ RTPrintf("tstPage: SUPPageAlloc(1,) failed rc=%d\n", rc);
+
+
+ //rc = SUPTerm();
+ cErrors += rc != 0;
+ if (rc)
+ RTPrintf("tstPage: SUPTerm failed rc=%d\n", rc);
+ }
+ else
+ RTPrintf("tstPage: SUPR3Init failed rc=%d\n", rc);
+
+ if (!cErrors)
+ RTPrintf("tstPage: SUCCESS\n");
+ else
+ RTPrintf("tstPage: FAILURE - %d errors\n", cErrors);
+ return !!cErrors;
+}
diff --git a/src/VBox/HostDrivers/Support/testcase/tstPin.cpp b/src/VBox/HostDrivers/Support/testcase/tstPin.cpp
new file mode 100644
index 000000000..553de4586
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/testcase/tstPin.cpp
@@ -0,0 +1,213 @@
+/** @file
+ *
+ * VBox host drivers - Ring-0 support drivers - Testcases:
+ * Test the memory locking interface
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <VBox/sup.h>
+#include <VBox/param.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <iprt/thread.h>
+#include <iprt/string.h>
+
+
+int main(int argc, char **argv)
+{
+ int rc;
+ int rcRet = 0;
+ RTHCPHYS HCPhys;
+
+ RTR3InitAndSUPLib();
+ rc = SUPR3Init(NULL);
+ RTPrintf("SUPR3Init -> rc=%d\n", rc);
+ rcRet += rc != 0;
+ if (!rc)
+ {
+ /*
+ * Simple test.
+ */
+ void *pv;
+ int rc = SUPPageAlloc(1, &pv);
+ AssertRC(rc);
+ RTPrintf("pv=%p\n", pv);
+ SUPPAGE aPages[1];
+ rc = SUPPageLock(pv, 1, &aPages[0]);
+ RTPrintf("rc=%d aPages[0]=%RHp\n", rc, pv, aPages[0]);
+ RTThreadSleep(1500);
+#if 0
+ RTPrintf("Unlocking...\n");
+ RTThreadSleep(250);
+ rc = SUPPageUnlock(pv);
+ RTPrintf("rc=%d\n", rc);
+ RTThreadSleep(1500);
+#endif
+
+ /*
+ * More extensive.
+ */
+ static struct
+ {
+ void *pv;
+ void *pvAligned;
+ SUPPAGE aPages[16];
+ } aPinnings[500];
+ for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i++)
+ {
+ aPinnings[i].pv = NULL;
+ SUPPageAlloc(0x10000 >> PAGE_SHIFT, &aPinnings[i].pv);
+ aPinnings[i].pvAligned = RT_ALIGN_P(aPinnings[i].pv, PAGE_SIZE);
+ rc = SUPPageLock(aPinnings[i].pvAligned, 0xf000 >> PAGE_SHIFT, &aPinnings[i].aPages[0]);
+ if (!rc)
+ {
+ RTPrintf("i=%d: pvAligned=%p pv=%p:\n", i, aPinnings[i].pvAligned, aPinnings[i].pv);
+ memset(aPinnings[i].pv, 0xfa, 0x10000);
+ unsigned c4GPluss = 0;
+ for (unsigned j = 0; j < (0xf000 >> PAGE_SHIFT); j++)
+ if (aPinnings[i].aPages[j].Phys >= _4G)
+ {
+ RTPrintf("%2d: vrt=%p phys=%RHp\n", j, (char *)aPinnings[i].pvAligned + (j << PAGE_SHIFT), aPinnings[i].aPages[j].Phys);
+ c4GPluss++;
+ }
+ RTPrintf("i=%d: c4GPluss=%d\n", i, c4GPluss);
+ }
+ else
+ {
+ RTPrintf("SUPPageLock -> rc=%d\n", rc);
+ rcRet++;
+ SUPPageFree(aPinnings[i].pv, 0x10000 >> PAGE_SHIFT);
+ aPinnings[i].pv = aPinnings[i].pvAligned = NULL;
+ break;
+ }
+ }
+
+ for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i += 2)
+ {
+ if (aPinnings[i].pvAligned)
+ {
+ rc = SUPPageUnlock(aPinnings[i].pvAligned);
+ if (rc)
+ {
+ RTPrintf("SUPPageUnlock(%p) -> rc=%d\n", aPinnings[i].pvAligned, rc);
+ rcRet++;
+ }
+ memset(aPinnings[i].pv, 0xaf, 0x10000);
+ }
+ }
+
+ for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i += 2)
+ {
+ if (aPinnings[i].pv)
+ {
+ memset(aPinnings[i].pv, 0xcc, 0x10000);
+ SUPPageFree(aPinnings[i].pv, 0x10000 >> PAGE_SHIFT);
+ aPinnings[i].pv = NULL;
+ }
+ }
+
+
+ /*
+ * Allocate a bit of contiguous memory.
+ */
+ pv = SUPContAlloc(RT_ALIGN_Z(15003, PAGE_SIZE) >> PAGE_SHIFT, &HCPhys);
+ rcRet += pv == NULL || HCPhys == 0;
+ if (pv && HCPhys)
+ {
+ RTPrintf("SUPContAlloc(15003) -> HCPhys=%llx pv=%p\n", HCPhys, pv);
+ void *pv0 = pv;
+ memset(pv0, 0xaf, 15003);
+ pv = SUPContAlloc(RT_ALIGN_Z(12999, PAGE_SIZE) >> PAGE_SHIFT, &HCPhys);
+ rcRet += pv == NULL || HCPhys == 0;
+ if (pv && HCPhys)
+ {
+ RTPrintf("SUPContAlloc(12999) -> HCPhys=%llx pv=%p\n", HCPhys, pv);
+ memset(pv, 0xbf, 12999);
+ rc = SUPContFree(pv, RT_ALIGN_Z(12999, PAGE_SIZE) >> PAGE_SHIFT);
+ rcRet += rc != 0;
+ if (rc)
+ RTPrintf("SUPContFree failed! rc=%d\n", rc);
+ }
+ else
+ RTPrintf("SUPContAlloc (2nd) failed!\n");
+ memset(pv0, 0xaf, 15003);
+ /* pv0 is intentionally not freed! */
+ }
+ else
+ RTPrintf("SUPContAlloc failed!\n");
+
+ /*
+ * Allocate a big chunk of virtual memory and then lock it.
+ */
+ #define BIG_SIZE 72*1024*1024
+ #define BIG_SIZEPP (BIG_SIZE + PAGE_SIZE)
+ pv = NULL;
+ SUPPageAlloc(BIG_SIZEPP >> PAGE_SHIFT, &pv);
+ if (pv)
+ {
+ static SUPPAGE aPages[BIG_SIZE >> PAGE_SHIFT];
+ void *pvAligned = RT_ALIGN_P(pv, PAGE_SIZE);
+ rc = SUPPageLock(pvAligned, BIG_SIZE >> PAGE_SHIFT, &aPages[0]);
+ if (!rc)
+ {
+ /* dump */
+ RTPrintf("SUPPageLock(%p,%d,) succeeded!\n", pvAligned, BIG_SIZE);
+ memset(pv, 0x42, BIG_SIZEPP);
+ #if 0
+ for (unsigned j = 0; j < (BIG_SIZE >> PAGE_SHIFT); j++)
+ RTPrintf("%2d: vrt=%p phys=%08x\n", j, (char *)pvAligned + (j << PAGE_SHIFT), (uintptr_t)aPages[j].pvPhys);
+ #endif
+
+ /* unlock */
+ rc = SUPPageUnlock(pvAligned);
+ if (rc)
+ {
+ RTPrintf("SUPPageUnlock(%p) -> rc=%d\n", pvAligned, rc);
+ rcRet++;
+ }
+ memset(pv, 0xcc, BIG_SIZEPP);
+ }
+ else
+ {
+ RTPrintf("SUPPageLock(%p) -> rc=%d\n", pvAligned, rc);
+ rcRet++;
+ }
+ SUPPageFree(pv, BIG_SIZEPP >> PAGE_SHIFT);
+ }
+
+ rc = SUPTerm();
+ RTPrintf("SUPTerm -> rc=%d\n", rc);
+ rcRet += rc != 0;
+ }
+
+ return rcRet;
+}
diff --git a/src/VBox/HostDrivers/Support/win/Makefile.kup b/src/VBox/HostDrivers/Support/win/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
new file mode 100644
index 000000000..5af79d3d2
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
@@ -0,0 +1,652 @@
+/* $Id: SUPDrv-win.cpp 13913 2008-11-06 12:59:01Z vboxsync $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#include "../SUPDrvInternal.h"
+#include <excpt.h>
+#include <iprt/assert.h>
+#include <iprt/process.h>
+#include <iprt/initterm.h>
+#include <iprt/power.h>
+#include <VBox/log.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The support service name. */
+#define SERVICE_NAME "VBoxDrv"
+/** Win32 Device name. */
+#define DEVICE_NAME "\\\\.\\VBoxDrv"
+/** NT Device name. */
+#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
+/** Win Symlink name. */
+#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
+/** The Pool tag (VBox). */
+#define SUPDRV_NT_POOL_TAG 'xoBV'
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+#if 0 //def RT_ARCH_AMD64
+typedef struct SUPDRVEXECMEM
+{
+ PMDL pMdl;
+ void *pvMapping;
+ void *pvAllocation;
+} SUPDRVEXECMEM, *PSUPDRVEXECMEM;
+#endif
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
+static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+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 VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
+static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
+
+/*******************************************************************************
+* External Functions *
+*******************************************************************************/
+DECLASM(int) UNWIND_WRAP(RTPowerSignalEvent)(RTPOWEREVENT enmEvent);
+
+/*******************************************************************************
+* Exported Functions *
+*******************************************************************************/
+__BEGIN_DECLS
+ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
+__END_DECLS
+
+
+/**
+ * Driver entry point.
+ *
+ * @returns appropriate status code.
+ * @param pDrvObj Pointer to driver object.
+ * @param pRegPath Registry base path.
+ */
+ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
+{
+ NTSTATUS rc;
+ dprintf(("VBoxDrv::DriverEntry\n"));
+
+ /*
+ * Create device.
+ * (That means creating a device object and a symbolic link so the DOS
+ * subsystems (OS/2, win32, ++) can access the device.)
+ */
+ UNICODE_STRING DevName;
+ RtlInitUnicodeString(&DevName, DEVICE_NAME_NT);
+ PDEVICE_OBJECT pDevObj;
+ rc = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
+ if (NT_SUCCESS(rc))
+ {
+ UNICODE_STRING DosName;
+ RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
+ rc = IoCreateSymbolicLink(&DosName, &DevName);
+ if (NT_SUCCESS(rc))
+ {
+ int vrc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the device extension.
+ */
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
+ memset(pDevExt, 0, sizeof(*pDevExt));
+
+ vrc = supdrvInitDevExt(pDevExt);
+ if (!vrc)
+ {
+ /*
+ * Setup the driver entry points in pDrvObj.
+ */
+ pDrvObj->DriverUnload = VBoxDrvNtUnload;
+ pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
+ pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
+ pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
+//#if 0 /** @todo test IDC on windows. */
+ pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
+//#endif
+ pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtNotSupportedStub;
+ pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
+
+ /* more? */
+
+ /* Register ourselves for power state changes. */
+ UNICODE_STRING CallbackName;
+ OBJECT_ATTRIBUTES Attr;
+
+ RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
+ InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ rc = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
+ if (rc == STATUS_SUCCESS)
+ pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback, VBoxPowerDispatchCallback, pDevObj);
+
+ dprintf(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
+ return STATUS_SUCCESS;
+ }
+
+ dprintf(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
+ rc = VBoxDrvNtErr2NtStatus(vrc);
+
+ IoDeleteSymbolicLink(&DosName);
+ RTR0Term();
+ }
+ else
+ {
+ dprintf(("RTR0Init failed with vrc=%d!\n", vrc));
+ rc = VBoxDrvNtErr2NtStatus(vrc);
+ }
+ }
+ else
+ dprintf(("IoCreateSymbolicLink failed with rc=%#x!\n", rc));
+
+ IoDeleteDevice(pDevObj);
+ }
+ else
+ dprintf(("IoCreateDevice failed with rc=%#x!\n", rc));
+
+ if (NT_SUCCESS(rc))
+ rc = STATUS_INVALID_PARAMETER;
+ dprintf(("VBoxDrv::DriverEntry returning %#x\n", rc));
+ return rc;
+}
+
+
+/**
+ * Unload the driver.
+ *
+ * @param pDrvObj Driver object.
+ */
+void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
+{
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDrvObj->DeviceObject->DeviceExtension;
+
+ dprintf(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
+
+ /* Clean up the power callback registration. */
+ if (pDevExt->hPowerCallback)
+ ExUnregisterCallback(pDevExt->hPowerCallback);
+ if (pDevExt->pObjPowerCallback)
+ ObDereferenceObject(pDevExt->pObjPowerCallback);
+
+ /*
+ * We ASSUME that it's not possible to unload a driver with open handles.
+ * Start by deleting the symbolic link
+ */
+ UNICODE_STRING DosName;
+ RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
+ NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
+
+ /*
+ * Terminate the GIP page and delete the device extension.
+ */
+ supdrvDeleteDevExt(pDevExt);
+ RTR0Term();
+ IoDeleteDevice(pDrvObj->DeviceObject);
+}
+
+
+/**
+ * Create (i.e. Open) file entry point.
+ *
+ * @param pDevObj Device object.
+ * @param pIrp Request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ dprintf(("VBoxDrvNtCreate\n"));
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PFILE_OBJECT pFileObj = pStack->FileObject;
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
+
+ /*
+ * We are not remotely similar to a directory...
+ * (But this is possible.)
+ */
+ if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
+ {
+ pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
+ pIrp->IoStatus.Information = 0;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ /*
+ * Call common code for the rest.
+ */
+ pFileObj->FsContext = NULL;
+ PSUPDRVSESSION pSession;
+//#if 0 /** @todo check if this works, consider OBJ_KERNEL_HANDLE too. */
+ bool fUser = pIrp->RequestorMode != KernelMode;
+//#else
+ // bool fUser = true;
+//#endif
+ int rc = supdrvCreateSession(pDevExt, fUser, &pSession);
+ if (!rc)
+ pFileObj->FsContext = pSession;
+
+ NTSTATUS rcNt = pIrp->IoStatus.Status = VBoxDrvNtErr2NtStatus(rc);
+ pIrp->IoStatus.Information = 0;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return rcNt;
+}
+
+
+/**
+ * Close file entry point.
+ *
+ * @param pDevObj Device object.
+ * @param pIrp Request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PFILE_OBJECT pFileObj = pStack->FileObject;
+ dprintf(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pSession=%p\n",
+ pDevExt, pFileObj, pFileObj->FsContext));
+ supdrvCloseSession(pDevExt, (PSUPDRVSESSION)pFileObj->FsContext);
+ pFileObj->FsContext = NULL;
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pDevObj Device object.
+ * @param pIrp Request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)pStack->FileObject->FsContext;
+
+ /*
+ * Deal with the two high-speed IOCtl that takes it's arguments from
+ * the session and iCmd, and only returns a VBox status code.
+ *
+ * Note: The previous method of returning the rc prior to IOC version
+ * 7.4 has been abandond, we're no longer compatible with that
+ * interface.
+ */
+ ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
+ if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
+ || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
+ || ulCmd == SUP_IOCTL_FAST_DO_NOP)
+ {
+ /* Raise the IRQL to DISPATCH_LEVEl to prevent Windows from rescheduling us to another CPU/core. */
+ Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+ KIRQL oldIrql;
+ KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
+ int rc = supdrvIOCtlFast(ulCmd, (uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
+ KeLowerIrql(oldIrql);
+
+ /* Complete the I/O request. */
+ NTSTATUS rcNt = pIrp->IoStatus.Status = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ return rcNt;
+ }
+
+ return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
+}
+
+
+/**
+ * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
+ *
+ * @returns NT status code.
+ *
+ * @param pDevObj Device object.
+ * @param pSession The session.
+ * @param pIrp Request packet.
+ * @param pStack The stack location containing the DeviceControl parameters.
+ */
+static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
+{
+ NTSTATUS rcNt;
+ unsigned cbOut = 0;
+ int rc = 0;
+ dprintf2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
+ pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
+ pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
+ pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
+
+#ifdef RT_ARCH_AMD64
+ /* Don't allow 32-bit processes to do any I/O controls. */
+ if (!IoIs32bitProcess(pIrp))
+#endif
+ {
+ /* Verify that it's a buffered CTL. */
+ if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
+ {
+ /* Verify that the sizes in the request header are correct. */
+ PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
+ if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
+ && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
+ && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
+ {
+ /*
+ * Do the job.
+ */
+ rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
+ if (!rc)
+ {
+ rcNt = STATUS_SUCCESS;
+ cbOut = pHdr->cbOut;
+ if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
+ {
+ cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
+ pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
+ }
+ }
+ else
+ rcNt = STATUS_INVALID_PARAMETER;
+ dprintf2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
+ }
+ else
+ {
+ dprintf(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
+ pStack->Parameters.DeviceIoControl.IoControlCode,
+ pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
+ pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
+ pStack->Parameters.DeviceIoControl.InputBufferLength,
+ pStack->Parameters.DeviceIoControl.OutputBufferLength));
+ rcNt = STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ dprintf(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
+ pStack->Parameters.DeviceIoControl.IoControlCode));
+ rcNt = STATUS_NOT_SUPPORTED;
+ }
+ }
+#ifdef RT_ARCH_AMD64
+ else
+ {
+ dprintf(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
+ rcNt = STATUS_NOT_SUPPORTED;
+ }
+#endif
+
+ /* complete the request. */
+ pIrp->IoStatus.Status = rcNt;
+ pIrp->IoStatus.Information = cbOut;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ return rcNt;
+}
+
+
+/**
+ * Internal Device I/O Control entry point, used for IDC.
+ *
+ * @param pDevObj Device object.
+ * @param pIrp Request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
+ PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+ PFILE_OBJECT pFileObj = pStack ? pStack->FileObject : NULL;
+ PSUPDRVSESSION pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
+ NTSTATUS rcNt;
+ unsigned cbOut = 0;
+ int rc = 0;
+ dprintf2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
+ pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
+ pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
+ pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
+
+/** @todo IDC on NT: figure when to create the session and that stuff... */
+
+ /* Verify that it's a buffered CTL. */
+ if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
+ {
+ /* Verify the pDevExt in the session. */
+ if ( ( !pSession
+ && pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
+ || ( VALID_PTR(pSession)
+ && pSession->pDevExt == pDevExt))
+ {
+ /* Verify that the size in the request header is correct. */
+ PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
+ if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
+ && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cb
+ && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
+ {
+ /*
+ * Do the job.
+ */
+ rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
+ if (!rc)
+ {
+ rcNt = STATUS_SUCCESS;
+ cbOut = pHdr->cb;
+ }
+ else
+ rcNt = STATUS_INVALID_PARAMETER;
+ dprintf2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
+ }
+ else
+ {
+ dprintf(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
+ pStack->Parameters.DeviceIoControl.IoControlCode,
+ pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
+ pStack->Parameters.DeviceIoControl.InputBufferLength,
+ pStack->Parameters.DeviceIoControl.OutputBufferLength));
+ rcNt = STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ rcNt = STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ dprintf(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
+ pStack->Parameters.DeviceIoControl.IoControlCode));
+ rcNt = STATUS_NOT_SUPPORTED;
+ }
+
+ /* complete the request. */
+ pIrp->IoStatus.Status = rcNt;
+ pIrp->IoStatus.Information = cbOut;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ return rcNt;
+}
+
+
+/**
+ * Stub function for functions we don't implemented.
+ *
+ * @returns STATUS_NOT_SUPPORTED
+ * @param pDevObj Device object.
+ * @param pIrp IRP.
+ */
+NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+ dprintf(("VBoxDrvNtNotSupportedStub\n"));
+ pDevObj = pDevObj;
+
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return STATUS_NOT_SUPPORTED;
+}
+
+
+/**
+ * ExRegisterCallback handler for power events
+ *
+ * @param pCallbackContext User supplied parameter (pDevObj)
+ * @param pArgument1 First argument
+ * @param pArgument2 Second argument
+ */
+VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2)
+{
+ PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;
+
+ dprintf(("VBoxPowerDispatchCallback: %x %x\n", pArgument1, pArgument2));
+
+ /* Power change imminent? */
+ if ((unsigned)pArgument1 == PO_CB_SYSTEM_STATE_LOCK)
+ {
+ if ((unsigned)pArgument2 == 0)
+ dprintf(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
+ else
+ dprintf(("VBoxPowerDispatchCallback: resumed!\n"));
+
+ /* Inform any clients that have registered themselves with IPRT. */
+ UNWIND_WRAP(RTPowerSignalEvent)(((unsigned)pArgument2 == 0) ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
+ }
+}
+
+
+/**
+ * Initializes any OS specific object creator fields.
+ */
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+/**
+ * Checks if the session can access the object.
+ *
+ * @returns true if a decision has been made.
+ * @returns false if the default access policy should be applied.
+ *
+ * @param pObj The object in question.
+ * @param pSession The session wanting to access the object.
+ * @param pszObjName The object name, can be NULL.
+ * @param prc Where to store the result when returning true.
+ */
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+/**
+ * Force async tsc mode (stub).
+ */
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ return false;
+}
+
+
+/**
+ * Converts a supdrv error code to an nt status code.
+ *
+ * @returns corresponding nt status code.
+ * @param rc supdrv error code (SUPDRV_ERR_* defines).
+ */
+static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
+{
+ switch (rc)
+ {
+ case 0: return STATUS_SUCCESS;
+ case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
+ case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
+ case SUPDRV_ERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
+ case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
+ case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
+ case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
+ case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
+ case SUPDRV_ERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
+ case SUPDRV_ERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
+ }
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+
+
+/** @todo use the nocrt stuff? */
+int VBOXCALL mymemcmp(const void *pv1, const void *pv2, size_t cb)
+{
+ const uint8_t *pb1 = (const uint8_t *)pv1;
+ const uint8_t *pb2 = (const uint8_t *)pv2;
+ for (; cb > 0; cb--, pb1++, pb2++)
+ if (*pb1 != *pb2)
+ return *pb1 - *pb2;
+ return 0;
+}
+
+
+#if 0 /* See alternative in SUPDrvA-win.asm */
+/**
+ * Alternative version of SUPR0Printf for Windows.
+ *
+ * @returns 0.
+ * @param pszFormat The format string.
+ */
+SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
+{
+ va_list va;
+ char szMsg[512];
+
+ va_start(va, pszFormat);
+ size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+ va_end(va);
+
+ RTLogWriteDebugger(szMsg, cch);
+ return 0;
+}
+#endif
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm b/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm
new file mode 100644
index 000000000..dc28974c4
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/SUPDrvA-win.asm
@@ -0,0 +1,328 @@
+; $Id$
+;; @file
+; VirtualBox Support Driver - Windows NT specific assembly parts.
+;
+
+;
+; Copyright (C) 2006-2007 Sun Microsystems, Inc.
+;
+; 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.
+;
+; Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+; Clara, CA 95054 USA or visit http://www.sun.com if you need
+; additional information or have any questions.
+;
+
+;*******************************************************************************
+;* Header Files *
+;*******************************************************************************
+%include "iprt/ntwrap.mac"
+
+BEGINCODE
+%ifdef RT_ARCH_AMD64
+%define _DbgPrint DbgPrint
+%endif
+extern _DbgPrint
+
+%if 1 ; see alternative in SUPDrv-win.cpp
+;;
+; Kind of alias for DbgPrint
+BEGINPROC SUPR0Printf
+ jmp _DbgPrint
+ENDPROC SUPR0Printf
+%endif
+
+
+%ifdef RT_WITH_W64_UNWIND_HACK
+ %ifdef RT_ARCH_AMD64
+
+;
+; This has the same order as the list in SUPDrv.c
+;
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ComponentRegisterFactory
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ComponentDeregisterFactory
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ComponentQueryFactory
+NtWrapDyn2DrvFunctionWith5Params supdrvNtWrap, SUPR0ObjRegister
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ObjAddRef
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ObjAddRefEx
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ObjRelease
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ObjVerifyAccess
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0LockMem
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0UnlockMem
+NtWrapDyn2DrvFunctionWith5Params supdrvNtWrap, SUPR0ContAlloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0ContFree
+NtWrapDyn2DrvFunctionWith5Params supdrvNtWrap, SUPR0LowAlloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0LowFree
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0MemAlloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0MemGetPhys
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0MemFree
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0PageAlloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0PageFree
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0Printf - cannot wrap this buster.
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, SUPR0GetPagingMode
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemAlloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemAllocZ
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemFree
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemDup
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemDupEx
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMemRealloc
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAllocLow
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAllocPage
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAllocPhys
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAllocPhysNC
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAllocCont
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjEnterPhys
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjLockUser
+NtWrapDyn2DrvFunctionWith5Params supdrvNtWrap, RTR0MemObjMapKernel
+NtWrapDyn2DrvFunctionWith7Params supdrvNtWrap, RTR0MemObjMapKernelEx
+NtWrapDyn2DrvFunctionWith6Params supdrvNtWrap, RTR0MemObjMapUser
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAddress - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjAddressR3 - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjSize - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjIsMapping - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjGetPagePhysAddr - not necessary
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0MemObjFree
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTProcSelf - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTR0ProcHandleSelf - not necessary
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemFastMutexCreate
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemFastMutexDestroy
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemFastMutexRequest
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemFastMutexRelease
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventCreate
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventSignal
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventWait
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventWaitNoResume
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventDestroy
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiCreate
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiSignal
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiReset
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiWait
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiWaitNoResume
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSemEventMultiDestroy
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockCreate
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockDestroy
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockAcquire
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockRelease
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockAcquireNoInts
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTSpinlockReleaseNoInts
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTTimeNanoTS - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTTimeMilliTS - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTTimeSystemNanoTS - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTTimeSystemMilliTS - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadNativeSelf - not necessary
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadSleep
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadYield
+%if 0 ; Thread APIs, Part 2
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadSelf
+NtWrapDyn2DrvFunctionWith7Params supdrvNtWrap, RTThreadCreate
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadGetNative
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadWait
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadWaitNoResume
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadGetName
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadSelfName
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadGetType
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadUserSignal
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadUserReset
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadUserWait
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTThreadUserWaitNoResume
+%endif
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogDefaultInstance - a bit of a gamble, but we do not want the overhead!
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpCpuId - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpCpuIdFromSetIndex - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpCpuIdToSetIndex - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpIsCpuPossible - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpGetCount - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpGetMaxCpuId - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpGetOnlineCount - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpGetOnlineSet - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpGetSet - not necessary
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpIsCpuOnline - not necessary
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpOnAll
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpOnOthers
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpOnSpecific
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTMpIsCpuWorkPending
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogRelDefaultInstance - not necessary.
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogSetDefaultInstanceThread
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogLogger - can't wrap this buster.
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogLoggerEx - can't wrap this buster.
+NtWrapDyn2DrvFunctionWith5Params supdrvNtWrap, RTLogLoggerExV
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogPrintf - can't wrap this buster. ;; @todo provide va_list log wrappers in RuntimeR0.
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, RTLogPrintfV
+NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, AssertMsg1
+;NtWrapDyn2DrvFunctionWithAllRegParams supdrvNtWrap, AssertMsg2 - can't wrap this buster.
+NtWrapDrv2DynFunctionWithAllRegParams supdrvNtWrap, RTPowerSignalEvent
+
+
+;;
+; @cproto DECLASM(int) supdrvNtWrapVMMR0EntryEx(PFNRT pfnVMMR0EntryEx, PVM pVM, unsigned uOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession);
+;
+; @param pfnVMMR0EntryEx rcx
+; @param pVM rdx
+; @param uOperation r8
+; @param pReq r9
+; @param u64Arg [rsp + 28h] / [rbp + 30h]
+; @param pSession [rsp + 30h] / [rbp + 38h]
+;
+BEGINPROC supdrvNtWrapVMMR0EntryEx
+ NtWrapProlog supdrvNtWrapVMMR0EntryEx
+ NtWrapCreateMarker
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+ mov r9, [rbp + 30h]
+ mov r11, [rbp + 38h]
+ mov [rsp + 20h], r11
+ call rax
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapVMMR0EntryEx
+ENDPROC supdrvNtWrapVMMR0EntryEx
+
+
+;;
+; @cproto DECLASM(int) supdrvNtWrapVMMR0EntryFast(PFNRT pfnVMMR0EntryFast, PVM pVM, unsigned idCPU, unsigned uOperation);
+;
+; @param pfnVMMR0EntryFast rcx
+; @param pVM rdx
+; @param idCPU r8
+; @param uOperation r9
+;
+BEGINPROC supdrvNtWrapVMMR0EntryFast
+ NtWrapProlog supdrvNtWrapVMMR0EntryFast
+ NtWrapCreateMarker
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+ call rax
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapVMMR0EntryFast
+ENDPROC supdrvNtWrapVMMR0EntryFast
+
+
+;;
+; @cproto DECLASM(void) supdrvNtWrapObjDestructor(PFNRT pfnDestruction, void *pvObj, void *pvUser1, void *pvUser2);
+;
+; @param pfnDestruction rcx
+; @param pvObj rdx
+; @param pvUser1 r8
+; @param pvUser2 r9
+;
+BEGINPROC supdrvNtWrapObjDestructor
+ NtWrapProlog supdrvNtWrapObjDestructor
+ NtWrapCreateMarker
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+ call rax
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapObjDestructor
+ENDPROC supdrvNtWrapObjDestructor
+
+
+;;
+; @cproto DECLASM(void *) supdrvNtWrapQueryFactoryInterface(PFNRT pfnQueryFactoryInterface, struct SUPDRVFACTORY const *pSupDrvFactory,
+; PSUPDRVSESSION pSession, const char *pszInterfaceUuid);
+;
+; @param pfnQueryFactoryInterface rcx
+; @param pSupDrvFactory rdx
+; @param pSession r8
+; @param pszInterfaceUuid r9
+;
+BEGINPROC supdrvNtWrapQueryFactoryInterface
+ NtWrapProlog supdrvNtWrapQueryFactoryInterface
+ NtWrapCreateMarker
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+ call rax
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapQueryFactoryInterface
+ENDPROC supdrvNtWrapQueryFactoryInterface
+
+
+;;
+; @cproto DECLASM(int) supdrvNtWrapModuleInit(PFNRT pfnModuleInit);
+;
+; @param pfnModuleInit rcx
+;
+BEGINPROC supdrvNtWrapModuleInit
+ NtWrapProlog supdrvNtWrapModuleInit
+ NtWrapCreateMarker
+
+ call rcx
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapModuleInit
+ENDPROC supdrvNtWrapModuleInit
+
+
+;;
+; @cproto DECLASM(void) supdrvNtWrapModuleTerm(PFNRT pfnModuleTerm);
+;
+; @param pfnModuleInit rcx
+;
+BEGINPROC supdrvNtWrapModuleTerm
+ NtWrapProlog supdrvNtWrapModuleTerm
+ NtWrapCreateMarker
+
+ call rcx
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapModuleTerm
+ENDPROC supdrvNtWrapModuleTerm
+
+
+;;
+; @cproto DECLASM(int) supdrvNtWrapServiceReqHandler(PFNRT pfnServiceReqHandler, PSUPDRVSESSION pSession, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr);
+;
+; @param pfnSerivceReqHandler rcx
+; @param pSession rdx
+; @param uOperation r8
+; @param u64Arg r9
+; @param pReq [rsp + 28h] / [rbp + 30h]
+;
+BEGINPROC supdrvNtWrapServiceReqHandler
+ NtWrapProlog supdrvNtWrapServiceReqHandler
+ NtWrapCreateMarker
+
+ mov rax, rcx
+ mov rcx, rdx
+ mov rdx, r8
+ mov r8, r9
+ mov r9, [rbp + 30h]
+ call rax
+
+ NtWrapDestroyMarker
+ NtWrapEpilog supdrvNtWrapServiceReqHandler
+ENDPROC supdrvNtWrapServiceReqHandler
+
+
+ %endif ; RT_ARCH_AMD64
+%endif ; RT_WITH_W64_UNWIND_HACK
+
diff --git a/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
new file mode 100644
index 000000000..1102570a6
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
@@ -0,0 +1,599 @@
+/* $Id: SUPLib-win.cpp 13865 2008-11-05 14:14:11Z vboxsync $ */
+/** @file
+ * VirtualBox Support Library - Windows NT specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# define LOG_DISABLED
+ /** @todo RTLOGREL_DISABLED */
+# include <iprt/log.h>
+# undef LogRelIt
+# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
+#endif
+
+#include <Windows.h>
+
+#include <VBox/sup.h>
+#include <VBox/types.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <VBox/log.h>
+#include <iprt/assert.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The support service name. */
+#define SERVICE_NAME "VBoxDrv"
+/** Win32 Device name. */
+#define DEVICE_NAME "\\\\.\\VBoxDrv"
+/** NT Device name. */
+#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
+/** Win32 Symlink name. */
+#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int suplibOsCreateService(void);
+//unused: static int suplibOsUpdateService(void);
+static int suplibOsDeleteService(void);
+static int suplibOsStartService(void);
+static int suplibOsStopService(void);
+static int suplibConvertWin32Err(int);
+
+
+
+
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
+{
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+
+ /*
+ * Try open the device.
+ */
+ HANDLE hDevice = CreateFile(DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ {
+#ifndef IN_SUP_HARDENED_R3
+ /*
+ * Try start the service and retry opening it.
+ */
+ suplibOsStartService();
+
+ hDevice = CreateFile(DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+#endif /* !IN_SUP_HARDENED_R3 */
+ {
+ int rc = GetLastError();
+ switch (rc)
+ {
+ /** @todo someone must test what is actually returned. */
+ case ERROR_DEV_NOT_EXIST:
+ case ERROR_DEVICE_NOT_CONNECTED:
+ case ERROR_BAD_DEVICE:
+ case ERROR_DEVICE_REMOVED:
+ case ERROR_DEVICE_NOT_AVAILABLE:
+ return VERR_VM_DRIVER_LOAD_ERROR;
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_FILE_NOT_FOUND:
+ return VERR_VM_DRIVER_NOT_INSTALLED;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ return VERR_VM_DRIVER_NOT_ACCESSIBLE;
+ default:
+ return VERR_VM_DRIVER_OPEN_ERROR;
+ }
+
+ return -1 /** @todo define proper error codes for suplibOsInit failure. */;
+ }
+ }
+
+ /*
+ * We're done.
+ */
+ pThis->hDevice = (RTFILE)hDevice;
+ return VINF_SUCCESS;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+int suplibOsInstall(void)
+{
+ return suplibOsCreateService();
+}
+
+
+int suplibOsUninstall(void)
+{
+ int rc = suplibOsStopService();
+ if (!rc)
+ rc = suplibOsDeleteService();
+ return rc;
+}
+
+
+/**
+ * Creates the service.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ */
+static int suplibOsCreateService(void)
+{
+ /*
+ * Assume it didn't exist, so we'll create the service.
+ */
+ SC_HANDLE hSMgrCreate = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(hSMgrCreate, ("OpenSCManager(,,create) failed rc=%d\n", LastError));
+ if (hSMgrCreate)
+ {
+ char szDriver[RTPATH_MAX];
+ int rc = RTPathProgram(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
+ if (RT_SUCCESS(rc))
+ {
+ strcat(szDriver, "\\VBoxDrv.sys");
+ SC_HANDLE hService = CreateService(hSMgrCreate,
+ SERVICE_NAME,
+ "VBox Support Driver",
+ SERVICE_QUERY_STATUS,
+ SERVICE_KERNEL_DRIVER,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ szDriver,
+ NULL, NULL, NULL, NULL, NULL);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(hService, ("CreateService failed! LastError=%Rwa szDriver=%s\n", LastError, szDriver));
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSMgrCreate);
+ return hService ? 0 : -1;
+ }
+ CloseServiceHandle(hSMgrCreate);
+ return rc;
+ }
+ return -1;
+}
+
+
+/**
+ * Stops a possibly running service.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ */
+static int suplibOsStopService(void)
+{
+ /*
+ * Assume it didn't exist, so we'll create the service.
+ */
+ int rc = -1;
+ SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_STOP | SERVICE_QUERY_STATUS);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", LastError));
+ if (hSMgr)
+ {
+ SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
+ if (hService)
+ {
+ /*
+ * Stop the service.
+ */
+ SERVICE_STATUS Status;
+ QueryServiceStatus(hService, &Status);
+ if (Status.dwCurrentState == SERVICE_STOPPED)
+ rc = 0;
+ else if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
+ {
+ int iWait = 100;
+ while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
+ {
+ Sleep(100);
+ QueryServiceStatus(hService, &Status);
+ }
+ if (Status.dwCurrentState == SERVICE_STOPPED)
+ rc = 0;
+ else
+ AssertMsgFailed(("Failed to stop service. status=%d\n", Status.dwCurrentState));
+ }
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("ControlService failed with LastError=%Rwa. status=%d\n", LastError, Status.dwCurrentState));
+ }
+ CloseServiceHandle(hService);
+ }
+ else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+ rc = 0;
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
+ }
+ CloseServiceHandle(hSMgr);
+ }
+ return rc;
+}
+
+
+/**
+ * Deletes the service.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ */
+int suplibOsDeleteService(void)
+{
+ /*
+ * Assume it didn't exist, so we'll create the service.
+ */
+ int rc = -1;
+ SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", LastError));
+ if (hSMgr)
+ {
+ SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, DELETE);
+ if (hService)
+ {
+ /*
+ * Delete the service.
+ */
+ if (DeleteService(hService))
+ rc = 0;
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("DeleteService failed LastError=%Rwa\n", LastError));
+ }
+ CloseServiceHandle(hService);
+ }
+ else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+ rc = 0;
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
+ }
+ CloseServiceHandle(hSMgr);
+ }
+ return rc;
+}
+
+#if 0
+/**
+ * Creates the service.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ */
+static int suplibOsUpdateService(void)
+{
+ /*
+ * Assume it didn't exist, so we'll create the service.
+ */
+ SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed LastError=%Rwa\n", LastError));
+ if (hSMgr)
+ {
+ SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_CHANGE_CONFIG);
+ if (hService)
+ {
+ char szDriver[RTPATH_MAX];
+ int rc = RTPathProgram(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
+ if (RT_SUCCESS(rc))
+ {
+ strcat(szDriver, "\\VBoxDrv.sys");
+
+ SC_LOCK hLock = LockServiceDatabase(hSMgr);
+ if (ChangeServiceConfig(hService,
+ SERVICE_KERNEL_DRIVER,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ szDriver,
+ NULL, NULL, NULL, NULL, NULL, NULL))
+ {
+
+ UnlockServiceDatabase(hLock);
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSMgr);
+ return 0;
+ }
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("ChangeServiceConfig failed LastError=%Rwa\n", LastError));
+ }
+ }
+ UnlockServiceDatabase(hLock);
+ CloseServiceHandle(hService);
+ }
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
+ }
+ CloseServiceHandle(hSMgr);
+ }
+ return -1;
+}
+#endif
+
+
+/**
+ * Attempts to start the service, creating it if necessary.
+ *
+ * @returns 0 on success.
+ * @returns -1 on failure.
+ * @param fRetry Indicates retry call.
+ */
+static int suplibOsStartService(void)
+{
+ /*
+ * Check if the driver service is there.
+ */
+ SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_START);
+ if (hSMgr == NULL)
+ {
+ AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode!\n"));
+ return -1;
+ }
+
+ /*
+ * Try open our service to check it's status.
+ */
+ SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
+ if (!hService)
+ {
+ /*
+ * Create the service.
+ */
+ int rc = suplibOsCreateService();
+ if (rc)
+ return rc;
+
+ /*
+ * Try open the service.
+ */
+ hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
+ }
+
+ /*
+ * Check if open and on demand create succeeded.
+ */
+ int rc = -1;
+ if (hService)
+ {
+
+ /*
+ * Query service status to see if we need to start it or not.
+ */
+ SERVICE_STATUS Status;
+ BOOL fRc = QueryServiceStatus(hService, &Status);
+ Assert(fRc);
+ if ( Status.dwCurrentState != SERVICE_RUNNING
+ && Status.dwCurrentState != SERVICE_START_PENDING)
+ {
+ /*
+ * Start it.
+ */
+ fRc = StartService(hService, 0, NULL);
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(fRc, ("StartService failed with LastError=%Rwa\n", LastError));
+ }
+
+ /*
+ * Wait for the service to finish starting.
+ * We'll wait for 10 seconds then we'll give up.
+ */
+ QueryServiceStatus(hService, &Status);
+ if (Status.dwCurrentState == SERVICE_START_PENDING)
+ {
+ int iWait;
+ for (iWait = 100; iWait > 0 && Status.dwCurrentState == SERVICE_START_PENDING; iWait--)
+ {
+ Sleep(100);
+ QueryServiceStatus(hService, &Status);
+ }
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsg(Status.dwCurrentState != SERVICE_RUNNING,
+ ("Failed to start. LastError=%Rwa iWait=%d status=%d\n",
+ LastError, iWait, Status.dwCurrentState));
+ }
+
+ if (Status.dwCurrentState == SERVICE_RUNNING)
+ rc = 0;
+
+ /*
+ * Close open handles.
+ */
+ CloseServiceHandle(hService);
+ }
+ else
+ {
+ DWORD LastError = GetLastError(); NOREF(LastError);
+ AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", LastError));
+ }
+ if (!CloseServiceHandle(hSMgr))
+ AssertFailed();
+
+ return rc;
+}
+
+
+int suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Check if we're initited at all.
+ */
+ if (pThis->hDevice != NIL_RTFILE)
+ {
+ if (!CloseHandle((HANDLE)pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = NIL_RTFILE;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ /*
+ * Issue the device I/O control.
+ */
+ PSUPREQHDR pHdr = (PSUPREQHDR)pvReq;
+ Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut));
+ DWORD cbReturned = (ULONG)pHdr->cbOut;
+ if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
+ return 0;
+ return suplibConvertWin32Err(GetLastError());
+}
+
+
+int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ /*
+ * Issue device I/O control.
+ */
+ DWORD cbReturned = 0;
+ if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
+ return VINF_SUCCESS;
+ return suplibConvertWin32Err(GetLastError());
+}
+
+
+int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
+{
+ NOREF(pThis);
+ *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (*ppvPages)
+ return VINF_SUCCESS;
+ return suplibConvertWin32Err(GetLastError());
+}
+
+
+int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
+{
+ NOREF(pThis);
+ if (VirtualFree(pvPages, 0, MEM_RELEASE))
+ return VINF_SUCCESS;
+ return suplibConvertWin32Err(GetLastError());
+}
+
+
+/**
+ * Converts a supdrv error code to an nt status code.
+ *
+ * @returns corresponding SUPDRV_ERR_*.
+ * @param rc Win32 error code.
+ */
+static int suplibConvertWin32Err(int rc)
+{
+ /* Conversion program (link with ntdll.lib from ddk):
+ #define _WIN32_WINNT 0x0501
+ #include <windows.h>
+ #include <ntstatus.h>
+ #include <winternl.h>
+ #include <stdio.h>
+
+ int main()
+ {
+ #define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
+ CONVERT(STATUS_SUCCESS);
+ CONVERT(STATUS_NOT_SUPPORTED);
+ CONVERT(STATUS_INVALID_PARAMETER);
+ CONVERT(STATUS_UNKNOWN_REVISION);
+ CONVERT(STATUS_INVALID_HANDLE);
+ CONVERT(STATUS_INVALID_ADDRESS);
+ CONVERT(STATUS_NOT_LOCKED);
+ CONVERT(STATUS_IMAGE_ALREADY_LOADED);
+ CONVERT(STATUS_ACCESS_DENIED);
+ CONVERT(STATUS_REVISION_MISMATCH);
+
+ return 0;
+ }
+ */
+
+ switch (rc)
+ {
+ //case 0: return STATUS_SUCCESS;
+ case 0: return VINF_SUCCESS;
+ //case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
+ case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
+ //case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
+ case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
+ //case SUPDRV_ERR_INVALID_MAGIC: return STATUS_ACCESS_DENIED;
+ case ERROR_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
+ //case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
+ case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
+ //case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
+ case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
+ //case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
+ case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
+ //case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
+ case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
+ //case SUPDRV_ERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
+ case ERROR_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
+ //case SUPDRV_ERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
+ case ERROR_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
+ }
+
+ /* fall back on the default conversion. */
+ return RTErrConvertFromWin32(rc);
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/win/SUPR0IdcClient-win.c b/src/VBox/HostDrivers/Support/win/SUPR0IdcClient-win.c
new file mode 100644
index 000000000..6021ecdd6
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/SUPR0IdcClient-win.c
@@ -0,0 +1,160 @@
+/* $Id: SUPR0IdcClient-win.c 10263 2008-07-05 00:26:17Z vboxsync $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Windows Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <VBox/err.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** NT Device name. */
+#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
+
+
+/**
+ * Internal I/O Control call worker.
+ *
+ * @returns VBox status code.
+ * @param pDeviceObject The device object to call.
+ * @param pFileObject The file object for the connection.
+ * @param uReq The request.
+ * @param pReq The request packet.
+ */
+static int supR0IdcNtCallInternal(PDEVICE_OBJECT pDeviceObject, PFILE_OBJECT pFileObject, uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc;
+ IO_STATUS_BLOCK IoStatusBlock;
+ KEVENT Event;
+ PIRP pIrp;
+ NTSTATUS rcNt;
+
+ /*
+ * Build the request.
+ */
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+ pIrp = IoBuildDeviceIoControlRequest(uReq, /* IoControlCode */
+ pDeviceObject,
+ pReq, /* InputBuffer */
+ pReq->cb, /* InputBufferLength */
+ pReq, /* OutputBuffer */
+ pReq->cb, /* OutputBufferLength */
+ TRUE, /* InternalDeviceIoControl (=> IRP_MJ_INTERNAL_DEVICE_CONTROL) */
+ &Event, /* Event */
+ &IoStatusBlock); /* IoStatusBlock */
+ if (pIrp)
+ {
+ IoGetNextIrpStackLocation(pIrp)->FileObject = pFileObject;
+
+ /*
+ * Call the driver, wait for an async request to complete (should never happen).
+ */
+ rcNt = IoCallDriver(pDeviceObject, pIrp);
+ if (rcNt == STATUS_PENDING)
+ {
+ rcNt = KeWaitForSingleObject(&Event, /* Object */
+ Executive, /* WaitReason */
+ KernelMode, /* WaitMode */
+ FALSE, /* Altertable */
+ NULL); /* TimeOut */
+ rcNt = IoStatusBlock.Status;
+ }
+ if (NT_SUCCESS(rcNt))
+ rc = pReq->rc;
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ return rc;
+}
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ PDEVICE_OBJECT pDeviceObject = NULL;
+ PFILE_OBJECT pFileObject = NULL;
+ UNICODE_STRING wszDeviceName;
+ NTSTATUS rcNt;
+ int rc;
+
+ /*
+ * Get the device object pointer.
+ */
+ RtlInitUnicodeString(&wszDeviceName, DEVICE_NAME_NT);
+ rcNt = IoGetDeviceObjectPointer(&wszDeviceName, FILE_ALL_ACCESS, &pFileObject, &pDeviceObject);
+ if (NT_SUCCESS(rcNt))
+ {
+ /*
+ * Make the connection call.
+ */
+ rc = supR0IdcNtCallInternal(pDeviceObject, pFileObject, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+ if (RT_SUCCESS(rc))
+ {
+ pHandle->s.pDeviceObject = pDeviceObject;
+ pHandle->s.pFileObject = pFileObject;
+ return rc;
+ }
+
+ /* only the file object. */
+ ObDereferenceObject(pFileObject);
+ }
+ else
+ rc = RTErrConvertFromNtStatus(rcNt);
+
+ pHandle->s.pDeviceObject = NULL;
+ pHandle->s.pFileObject = NULL;
+ return rc;
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ PFILE_OBJECT pFileObject = pHandle->s.pFileObject;
+ int rc = supR0IdcNtCallInternal(pHandle->s.pDeviceObject, pFileObject, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+ if (RT_SUCCESS(rc))
+ {
+ pHandle->s.pDeviceObject = NULL;
+ pHandle->s.pFileObject = NULL;
+ ObDereferenceObject(pFileObject);
+ }
+
+ return rc;
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNtCallInternal(pHandle->s.pDeviceObject, pHandle->s.pFileObject, uReq, pReq);
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp b/src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp
new file mode 100644
index 000000000..fae7d49d0
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/SUPSvc-win.cpp
@@ -0,0 +1,900 @@
+/* $Id: SUPSvc-win.cpp 14303 2008-11-18 13:45:38Z vboxsync $ */
+/** @file
+ * VirtualBox Support Service - Windows Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#include <Windows.h>
+
+#include <VBox/log.h>
+#include <VBox/version.h>
+#include <iprt/string.h>
+#include <iprt/mem.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#include <iprt/getopt.h>
+#include <iprt/semaphore.h>
+#ifdef DEBUG_bird
+# include <iprt/env.h>
+#endif
+
+#include "../SUPSvcInternal.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The service name. */
+#define SUPSVC_SERVICE_NAME "VBoxSupSvc"
+/** The service display name. */
+#define SUPSVC_SERVICE_DISPLAY_NAME "VirtualBox Support Service"
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The service control handler handle. */
+static SERVICE_STATUS_HANDLE g_hSupSvcWinCtrlHandler = NULL;
+/** The service status. */
+static uint32_t volatile g_u32SupSvcWinStatus = SERVICE_STOPPED;
+/** The semaphore the main service thread is waiting on in supSvcWinServiceMain. */
+static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
+
+
+/**
+ * Opens the service control manager.
+ *
+ * When this fails, an error message will be displayed.
+ *
+ * @returns Valid handle on success.
+ * NULL on failure, will display an error message.
+ *
+ * @param pszAction The action which is requesting access to SCM.
+ * @param dwAccess The desired access.
+ */
+static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess)
+{
+ SC_HANDLE hSCM = OpenSCManager(NULL /* lpMachineName*/, NULL /* lpDatabaseName */, dwAccess);
+ if (hSCM == NULL)
+ {
+ DWORD err = GetLastError();
+ switch (err)
+ {
+ case ERROR_ACCESS_DENIED:
+ supSvcDisplayError("%s - OpenSCManager failure: access denied\n", pszAction);
+ break;
+ default:
+ supSvcDisplayError("%s - OpenSCManager failure: %d\n", pszAction, err);
+ break;
+ }
+ }
+ return hSCM;
+}
+
+
+/**
+ * Opens the service.
+ *
+ * Last error is preserved on failure and set to 0 on success.
+ *
+ * @returns Valid service handle on success.
+ * NULL on failure, will display an error message unless it's ignored.
+ *
+ * @param pszAction The action which is requestion access to the service.
+ * @param dwSCMAccess The service control manager access.
+ * @param dwSVCAccess The desired service access.
+ * @param cIgnoredErrors The number of ignored errors.
+ * @param ... Errors codes that should not cause a message to be displayed.
+ */
+static SC_HANDLE supSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
+ unsigned cIgnoredErrors, ...)
+{
+ SC_HANDLE hSCM = supSvcWinOpenSCManager(pszAction, dwSCMAccess);
+ if (!hSCM)
+ return NULL;
+
+ SC_HANDLE hSvc = OpenService(hSCM, SUPSVC_SERVICE_NAME, dwSVCAccess);
+ if (hSvc)
+ {
+ CloseServiceHandle(hSCM);
+ SetLastError(0);
+ }
+ else
+ {
+ DWORD err = GetLastError();
+ bool fIgnored = false;
+ va_list va;
+ va_start(va, cIgnoredErrors);
+ while (!fIgnored && cIgnoredErrors-- > 0)
+ fIgnored = va_arg(va, long) == err;
+ va_end(va);
+ if (!fIgnored)
+ {
+ switch (err)
+ {
+ case ERROR_ACCESS_DENIED:
+ supSvcDisplayError("%s - OpenService failure: access denied\n", pszAction);
+ break;
+ case ERROR_SERVICE_DOES_NOT_EXIST:
+ supSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction);
+ break;
+ default:
+ supSvcDisplayError("%s - OpenService failure: %d\n", pszAction, err);
+ break;
+ }
+ }
+
+ CloseServiceHandle(hSCM);
+ SetLastError(err);
+ }
+ return hSvc;
+}
+
+
+
+void supSvcOsLogErrorStr(const char *pszMsg)
+{
+ HANDLE hEventLog = RegisterEventSource(NULL /* local computer */, "VBoxSupSvc");
+ AssertReturnVoid(hEventLog != NULL);
+ const char *apsz[2];
+ apsz[0] = "VBoxSupSvc";
+ apsz[1] = pszMsg;
+ BOOL fRc = ReportEvent(hEventLog, /* hEventLog */
+ EVENTLOG_ERROR_TYPE, /* wType */
+ 0, /* wCategory */
+ 0 /** @todo mc */, /* dwEventID */
+ NULL, /* lpUserSid */
+ RT_ELEMENTS(apsz), /* wNumStrings */
+ 0, /* dwDataSize */
+ apsz, /* lpStrings */
+ NULL); /* lpRawData */
+ AssertMsg(fRc, ("%d\n", GetLastError()));
+ DeregisterEventSource(hEventLog);
+}
+
+
+static int supSvcWinInterrogate(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"interrogate\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinStop(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"stop\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinContinue(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"continue\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinPause(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"pause\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinStart(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"start\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinQueryDescription(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"qdescription\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinQueryConfig(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"qconfig\" action is not implemented.\n");
+ return 1;
+}
+
+
+static int supSvcWinDisable(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"disable\" action is not implemented.\n");
+ return 1;
+}
+
+static int supSvcWinEnable(int argc, char **argv)
+{
+ RTPrintf("VBoxSupSvc: The \"enable\" action is not implemented.\n");
+ return 1;
+}
+
+
+/**
+ * Handle the 'delete' action.
+ *
+ * @returns 0 or 1.
+ * @param argc The action argument count.
+ * @param argv The action argument vector.
+ */
+static int supSvcWinDelete(int argc, char **argv)
+{
+ /*
+ * Parse the arguments.
+ */
+ bool fVerbose = false;
+ static const RTOPTIONDEF s_aOptions[] =
+ {
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ };
+ int iArg = 0;
+ int ch;
+ RTOPTIONUNION Value;
+ while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
+ switch (ch)
+ {
+ case 'v': fVerbose = true; break;
+ default: return supSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
+ }
+ if (iArg != argc)
+ return supSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
+
+ /*
+ * Create the service.
+ */
+ int rc = 1;
+ SC_HANDLE hSvc = supSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
+ 1, ERROR_SERVICE_DOES_NOT_EXIST);
+ if (hSvc)
+ {
+ if (DeleteService(hSvc))
+ {
+ RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
+ rc = 0;
+ }
+ else
+ supSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError());
+ CloseServiceHandle(hSvc);
+ }
+ else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+
+ if (fVerbose)
+ RTPrintf("The service %s was not installed, nothing to be done.", SUPSVC_SERVICE_NAME);
+ else
+ RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME);
+ rc = 0;
+ }
+ return rc;
+}
+
+
+/**
+ * Handle the 'create' action.
+ *
+ * @returns 0 or 1.
+ * @param argc The action argument count.
+ * @param argv The action argument vector.
+ */
+static int supSvcWinCreate(int argc, char **argv)
+{
+ /*
+ * Parse the arguments.
+ */
+ bool fVerbose = false;
+ static const RTOPTIONDEF s_aOptions[] =
+ {
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ };
+ int iArg = 0;
+ int ch;
+ RTOPTIONUNION Value;
+ while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
+ switch (ch)
+ {
+ case 'v': fVerbose = true; break;
+ default: return supSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
+ }
+ if (iArg != argc)
+ return supSvcDisplayTooManyArgsError("create", argc, argv, iArg);
+
+ /*
+ * Create the service.
+ */
+ int rc = 1;
+ SC_HANDLE hSCM = supSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/
+ if (hSCM)
+ {
+ char szExecPath[MAX_PATH];
+ if (GetModuleFileName(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
+ {
+ if (fVerbose)
+ RTPrintf("Creating the %s service, binary \"%s\"...\n",
+ SUPSVC_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
+
+ SC_HANDLE hSvc = CreateService(hSCM, /* hSCManager */
+ SUPSVC_SERVICE_NAME, /* lpServiceName */
+ SUPSVC_SERVICE_DISPLAY_NAME, /* lpDisplayName */
+ SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
+ SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
+ SERVICE_DEMAND_START/*_AUTO*/, /* dwStartType */
+ SERVICE_ERROR_NORMAL, /* dwErrorControl */
+ szExecPath, /* lpBinaryPathName */
+ NULL, /* lpLoadOrderGroup */
+ NULL, /* lpdwTagId */
+ NULL, /* lpDependencies */
+ NULL, /* lpServiceStartName (=> LocalSystem) */
+ NULL); /* lpPassword */
+ if (hSvc)
+ {
+ RTPrintf("Successfully created the %s service.\n", SUPSVC_SERVICE_NAME);
+ /** @todo Set the service description or it'll look weird in the vista service manager.
+ * Anything else that should be configured? Start access or something? */
+ rc = 0;
+ CloseServiceHandle(hSvc);
+ }
+ else
+ {
+ DWORD err = GetLastError();
+ switch (err)
+ {
+ case ERROR_SERVICE_EXISTS:
+ supSvcDisplayError("create - The service already exists.\n");
+ break;
+ default:
+ supSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError());
+ break;
+ }
+ }
+ CloseServiceHandle(hSvc);
+ }
+ else
+ supSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError());
+ }
+ return rc;
+}
+
+
+/**
+ * Sets the service status, just a SetServiceStatus Wrapper.
+ *
+ * @returns See SetServiceStatus.
+ * @param dwStatus The current status.
+ * @param iWaitHint The wait hint, if < 0 then supply a default.
+ * @param dwExitCode The service exit code.
+ */
+static bool supSvcWinSetServiceStatus(DWORD dwStatus, int iWaitHint, DWORD dwExitCode)
+{
+ SERVICE_STATUS SvcStatus;
+ SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ SvcStatus.dwWin32ExitCode = dwExitCode;
+ SvcStatus.dwServiceSpecificExitCode = 0;
+ SvcStatus.dwWaitHint = iWaitHint >= 0 ? iWaitHint : 3000;
+ SvcStatus.dwCurrentState = dwStatus;
+ LogFlow(("supSvcWinSetServiceStatus: %d -> %d\n", g_u32SupSvcWinStatus, dwStatus));
+ g_u32SupSvcWinStatus = dwStatus;
+ switch (dwStatus)
+ {
+ case SERVICE_START_PENDING:
+ SvcStatus.dwControlsAccepted = 0;
+ break;
+ default:
+ SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+ break;
+ }
+
+ static DWORD dwCheckPoint = 0;
+ switch (dwStatus)
+ {
+ case SERVICE_RUNNING:
+ case SERVICE_STOPPED:
+ SvcStatus.dwCheckPoint = 0;
+ default:
+ SvcStatus.dwCheckPoint = ++dwCheckPoint;
+ break;
+ }
+ return SetServiceStatus(g_hSupSvcWinCtrlHandler, &SvcStatus) != FALSE;
+}
+
+
+/**
+ * Service control handler (extended).
+ *
+ * @returns Windows status (see HandlerEx).
+ * @retval NO_ERROR if handled.
+ * @retval ERROR_CALL_NOT_IMPLEMENTED if not handled.
+ *
+ * @param dwControl The control code.
+ * @param dwEventType Event type. (specific to the control?)
+ * @param pvEventData Event data, specfic to the event.
+ * @param pvContext The context pointer registered with the handler.
+ * Currently not used.
+ */
+static DWORD WINAPI supSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
+{
+ LogFlow(("supSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
+ dwControl, dwEventType, pvEventData));
+
+ switch (dwControl)
+ {
+ /*
+ * Interrogate the service about it's current status.
+ * MSDN says that this should just return NO_ERROR and does
+ * not need to set the status again.
+ */
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+
+ /*
+ * Request to stop the service.
+ */
+ case SERVICE_CONTROL_STOP:
+ {
+ /*
+ * Check if the real services can be stopped and then tell them to stop.
+ */
+ supSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
+ int rc = supSvcTryStopServices();
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Notify the main thread that we're done, it will wait for the
+ * real services to stop, destroy them, and finally set the windows
+ * service status to SERVICE_STOPPED and return.
+ */
+ rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
+ if (RT_FAILURE(rc))
+ supSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
+ }
+ return NO_ERROR;
+ }
+
+ case SERVICE_CONTROL_PAUSE:
+ case SERVICE_CONTROL_CONTINUE:
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_PARAMCHANGE:
+ case SERVICE_CONTROL_NETBINDADD:
+ case SERVICE_CONTROL_NETBINDREMOVE:
+ case SERVICE_CONTROL_NETBINDENABLE:
+ case SERVICE_CONTROL_NETBINDDISABLE:
+ case SERVICE_CONTROL_DEVICEEVENT:
+ case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
+ case SERVICE_CONTROL_POWEREVENT:
+ case SERVICE_CONTROL_SESSIONCHANGE:
+#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
+ case SERVICE_CONTROL_PRESHUTDOWN:
+#endif
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ NOREF(dwEventType);
+ NOREF(pvEventData);
+ NOREF(pvContext);
+ return NO_ERROR;
+}
+
+
+/**
+ * Windows Service Main.
+ *
+ * This is invoked when the service is started and should not return until
+ * the service has been stopped.
+ *
+ * @param cArgs Argument count.
+ * @param papszArgs Argument vector.
+ */
+static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Register the control handler function for the service and report to SCM.
+ */
+ Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
+ g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
+ if (g_hSupSvcWinCtrlHandler)
+ {
+ DWORD err = ERROR_GEN_FAILURE;
+ if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
+ {
+ /*
+ * Parse arguments.
+ */
+ static const RTOPTIONDEF s_aOptions[] =
+ {
+ { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
+ };
+ int iArg = 1; /* the first arg is the service name */
+ int ch;
+ int rc = 0;
+ RTOPTIONUNION Value;
+ while ( !rc
+ && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
+ switch (ch)
+ {
+ default: rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
+ }
+ if (iArg != cArgs)
+ rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
+ if (!rc)
+ {
+ /*
+ * Create the event semaphore we'll be waiting on and
+ * then instantiate the actual services.
+ */
+ int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = supSvcCreateAndStartServices();
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Update the status and enter the work loop.
+ *
+ * The work loop is just a dummy wait here as the services run
+ * in independant threads.
+ */
+ if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
+ {
+ LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
+ rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ LogFlow(("supSvcWinServiceMain: woke up\n"));
+ err = NO_ERROR;
+ }
+ else
+ supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
+ }
+ else
+ {
+ err = GetLastError();
+ supSvcLogError("SetServiceStatus failed, err=%d", err);
+ }
+
+ /*
+ * Destroy the service instances, stopping them if
+ * they're still running (weird failure cause).
+ */
+ supSvcStopAndDestroyServices();
+ }
+
+ RTSemEventMultiDestroy(g_hSupSvcWinEvent);
+ g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
+ }
+ else
+ supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
+ }
+ /* else: bad args */
+ }
+ else
+ {
+ err = GetLastError();
+ supSvcLogError("SetServiceStatus failed, err=%d", err);
+ }
+ supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
+ }
+ else
+ supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
+ LogFlowFuncLeave();
+}
+
+
+/**
+ * Handle the 'create' action.
+ *
+ * @returns 0 or 1.
+ * @param argc The action argument count.
+ * @param argv The action argument vector.
+ */
+static int supSvcWinRunIt(int argc, char **argv)
+{
+ LogFlowFuncEnter();
+
+ /*
+ * Initialize release logging.
+ */
+ /** @todo release logging of the system-wide service. */
+
+ /*
+ * Parse the arguments.
+ */
+ static const RTOPTIONDEF s_aOptions[] =
+ {
+ { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
+ };
+ int iArg = 0;
+ int ch;
+ RTOPTIONUNION Value;
+ while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
+ switch (ch)
+ {
+ default: return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
+ }
+ if (iArg != argc)
+ return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
+
+ /*
+ * Register the service with the service control manager
+ * and start dispatching requests from it (all done by the API).
+ */
+ static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
+ {
+ { SUPSVC_SERVICE_NAME, supSvcWinServiceMain },
+ { NULL, NULL}
+ };
+ if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
+ {
+ LogFlowFuncLeave();
+ return 0; /* told to quit, so quit. */
+ }
+
+ DWORD err = GetLastError();
+ switch (err)
+ {
+ case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
+ supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
+ break;
+ default:
+ supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
+ break;
+ }
+ return 1;
+}
+
+
+/**
+ * Show the version info.
+ *
+ * @returns 0.
+ */
+static int supSvcWinShowVersion(int argc, char **argv)
+{
+ /*
+ * Parse the arguments.
+ */
+ bool fBrief = false;
+ static const RTOPTIONDEF s_aOptions[] =
+ {
+ { "--brief", 'b', RTGETOPT_REQ_NOTHING }
+ };
+ int iArg = 0;
+ int ch;
+ RTOPTIONUNION Value;
+ while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
+ switch (ch)
+ {
+ case 'b': fBrief = true; break;
+ default: return supSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
+
+ }
+ if (iArg != argc)
+ return supSvcDisplayTooManyArgsError("version", argc, argv, iArg);
+
+ /*
+ * Do the printing.
+ */
+ if (fBrief)
+ RTPrintf("%s\n", VBOX_VERSION_STRING);
+ else
+ RTPrintf("VirtualBox System Service Version %s\n"
+ "(C) 2008 Sun Microsystems, Inc.\n"
+ "All rights reserved.\n",
+ VBOX_VERSION_STRING);
+ return 0;
+}
+
+
+/**
+ * Show the usage help screen.
+ *
+ * @returns 0.
+ */
+static int supSvcWinShowHelp(void)
+{
+ RTPrintf("VirtualBox System Service Version %s\n"
+ "(C) 2008 Sun Microsystems, Inc.\n"
+ "All rights reserved.\n"
+ "\n",
+ VBOX_VERSION_STRING);
+ RTPrintf("Usage:\n"
+ "\n"
+ "VBoxSupSvc\n"
+ " Runs the service.\n"
+ "VBoxSupSvc <version|-v|--version> [-brief]\n"
+ " Displays the version.\n"
+ "VBoxSupSvc <help|-?|-h|--help> [...]\n"
+ " Displays this help screen.\n"
+ "\n"
+ "VBoxSupSvc <install|/RegServer|/i>\n"
+ " Installs the service.\n"
+ "VBoxSupSvc <install|delete|/UnregServer|/u>\n"
+ " Uninstalls the service.\n"
+ );
+ return 0;
+}
+
+
+/**
+ * VBoxSUPSvc main(), Windows edition.
+ *
+ *
+ * @returns 0 on success.
+ *
+ * @param argc Number of arguments in argv.
+ * @param argv Argument vector.
+ */
+int main(int argc, char **argv)
+{
+ /*
+ * Initialize the IPRT first of all.
+ */
+#ifdef DEBUG_bird
+ RTEnvSet("VBOX_LOG", "sup=~0");
+ RTEnvSet("VBOX_LOG_DEST", "file=E:\\temp\\VBoxSupSvc.log");
+ RTEnvSet("VBOX_LOG_FLAGS", "unbuffered thread msprog");
+#endif
+ int rc = RTR3Init();
+ if (RT_FAILURE(rc))
+ {
+ supSvcLogError("RTR3Init failed with rc=%Rrc", rc);
+ return 1;
+ }
+
+ /*
+ * Parse the initial arguments to determin the desired action.
+ */
+ enum
+ {
+ kSupSvcAction_RunIt,
+
+ kSupSvcAction_Create,
+ kSupSvcAction_Delete,
+
+ kSupSvcAction_Enable,
+ kSupSvcAction_Disable,
+ kSupSvcAction_QueryConfig,
+ kSupSvcAction_QueryDescription,
+
+ kSupSvcAction_Start,
+ kSupSvcAction_Pause,
+ kSupSvcAction_Continue,
+ kSupSvcAction_Stop,
+ kSupSvcAction_Interrogate,
+
+ kSupSvcAction_End
+ } enmAction = kSupSvcAction_RunIt;
+ int iArg = 1;
+ if (argc > 1)
+ {
+ if ( !stricmp(argv[iArg], "/RegServer")
+ || !stricmp(argv[iArg], "install")
+ || !stricmp(argv[iArg], "/i"))
+ enmAction = kSupSvcAction_Create;
+ else if ( !stricmp(argv[iArg], "/UnregServer")
+ || !stricmp(argv[iArg], "/u")
+ || !stricmp(argv[iArg], "uninstall")
+ || !stricmp(argv[iArg], "delete"))
+ enmAction = kSupSvcAction_Delete;
+
+ else if (!stricmp(argv[iArg], "enable"))
+ enmAction = kSupSvcAction_Enable;
+ else if (!stricmp(argv[iArg], "disable"))
+ enmAction = kSupSvcAction_Disable;
+ else if (!stricmp(argv[iArg], "qconfig"))
+ enmAction = kSupSvcAction_QueryConfig;
+ else if (!stricmp(argv[iArg], "qdescription"))
+ enmAction = kSupSvcAction_QueryDescription;
+
+ else if ( !stricmp(argv[iArg], "start")
+ || !stricmp(argv[iArg], "/t"))
+ enmAction = kSupSvcAction_Start;
+ else if (!stricmp(argv[iArg], "pause"))
+ enmAction = kSupSvcAction_Start;
+ else if (!stricmp(argv[iArg], "continue"))
+ enmAction = kSupSvcAction_Continue;
+ else if (!stricmp(argv[iArg], "stop"))
+ enmAction = kSupSvcAction_Stop;
+ else if (!stricmp(argv[iArg], "interrogate"))
+ enmAction = kSupSvcAction_Interrogate;
+ else if ( !stricmp(argv[iArg], "help")
+ || !stricmp(argv[iArg], "?")
+ || !stricmp(argv[iArg], "/?")
+ || !stricmp(argv[iArg], "-?")
+ || !stricmp(argv[iArg], "/h")
+ || !stricmp(argv[iArg], "-h")
+ || !stricmp(argv[iArg], "/help")
+ || !stricmp(argv[iArg], "-help")
+ || !stricmp(argv[iArg], "--help"))
+ return supSvcWinShowHelp();
+ else if ( !stricmp(argv[iArg], "version")
+ || !stricmp(argv[iArg], "/v")
+ || !stricmp(argv[iArg], "-v")
+ || !stricmp(argv[iArg], "/version")
+ || !stricmp(argv[iArg], "-version")
+ || !stricmp(argv[iArg], "--version"))
+ return supSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
+ else
+ iArg--;
+ iArg++;
+ }
+
+ /*
+ * Dispatch it.
+ */
+ switch (enmAction)
+ {
+ case kSupSvcAction_RunIt:
+ return supSvcWinRunIt(argc - iArg, argv + iArg);
+
+ case kSupSvcAction_Create:
+ return supSvcWinCreate(argc - iArg, argv + iArg);
+ case kSupSvcAction_Delete:
+ return supSvcWinDelete(argc - iArg, argv + iArg);
+
+ case kSupSvcAction_Enable:
+ return supSvcWinEnable(argc - iArg, argv + iArg);
+ case kSupSvcAction_Disable:
+ return supSvcWinDisable(argc - iArg, argv + iArg);
+ case kSupSvcAction_QueryConfig:
+ return supSvcWinQueryConfig(argc - iArg, argv + iArg);
+ case kSupSvcAction_QueryDescription:
+ return supSvcWinQueryDescription(argc - iArg, argv + iArg);
+
+ case kSupSvcAction_Start:
+ return supSvcWinStart(argc - iArg, argv + iArg);
+ case kSupSvcAction_Pause:
+ return supSvcWinPause(argc - iArg, argv + iArg);
+ case kSupSvcAction_Continue:
+ return supSvcWinContinue(argc - iArg, argv + iArg);
+ case kSupSvcAction_Stop:
+ return supSvcWinStop(argc - iArg, argv + iArg);
+ case kSupSvcAction_Interrogate:
+ return supSvcWinInterrogate(argc - iArg, argv + iArg);
+
+ default:
+ AssertMsgFailed(("enmAction=%d\n", enmAction));
+ return 1;
+ }
+}
+
diff --git a/src/VBox/HostDrivers/Support/win/VBoxDrv.inf b/src/VBox/HostDrivers/Support/win/VBoxDrv.inf
new file mode 100644
index 000000000..f2abe5db8
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/win/VBoxDrv.inf
@@ -0,0 +1,73 @@
+;
+; VBox host drivers - Ring-0 support drivers - Win32 host
+;
+; INF file for installing the Win32 driver
+;
+; Copyright (C) 2006-2007 Sun Microsystems, Inc.
+;
+; 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.
+;
+; Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+; Clara, CA 95054 USA or visit http://www.sun.com if you need
+; additional information or have any questions.
+;
+
+[Version]
+Signature="$Windows NT$"
+Class=System
+ClassGuid={ce4a90b5-1d8c-435d-b349-232ce55cb17f}
+Provider=%SUN%
+;edit-DriverVer=08/26/2008,2.00.0000
+DriverPackageType=KernelService
+;cat CatalogFile=VBoxDrv.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+[DefaultInstall]
+CopyFiles=VBoxDrv.CopyFiles
+
+[DefaultInstall.Services]
+AddService=VBoxDrv,0x00000002,VBoxDrv_Service
+
+[Manufacturer]
+;x86 %SUN%=SUN
+;amd64 %SUN%=SUN, NTamd64
+
+[SourceDisksFiles]
+VBoxDrv.sys=1
+
+[SourceDisksNames]
+1=%DISK_NAME%,
+
+[VBoxDrv.CopyFiles]
+VBoxDrv.sys
+
+[VBoxDrv_Service]
+DisplayName = %VBoxDrv.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+;StartType = 3 ; SERVICE_DEMAND_START
+StartType = 1 ; autostart to fix Vista problem
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxDrv.sys
+
+[Strings]
+SUN = "Sun Microsystems, Inc."
+VBoxDrv.SVCDESC = "VirtualBox Service"
+VBoxDrv.DRVDESC = "VirtualBox Driver"
+DISK_NAME = "VirtualBox Driver Installation Disk"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk b/src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk
new file mode 100644
index 000000000..0f1fdf72d
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/Makefile.kmk
@@ -0,0 +1,314 @@
+# $Id: Makefile.kmk 15949 2009-01-14 18:21:43Z vboxsync $
+## @file
+# Sub-Makefile for the Network Filter Driver (VBoxNetFlt).
+#
+
+#
+# Copyright (C) 2008 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+
+if1of ($(KBUILD_TARGET), darwin win)
+#
+# VBoxNetFlt.sys - The mixed case driver.
+#
+SYSMODS += VBoxNetFlt
+VBoxNetFlt_TEMPLATE = VBOXR0DRV
+VBoxNetFlt_INST = $(INST_VBOXNETFLT)$(if $(eq $(KBUILD_TARGET),darwin),Contents/MacOS/)
+if defined(VBOX_SIGNING_MODE) && "$(KBUILD_TARGET)" == "win"
+ VBoxNetFlt_NOINST = true
+endif
+VBoxNetFlt_DEFS = IN_RT_R0 VBOX_SVN_REV=$(VBOX_SVN_REV) IN_SUP_STATIC
+VBoxNetFlt_SDKS.win = W2K3DDK WINPSDKINCS
+VBoxNetFlt_INCS := $(PATH_SUB_CURRENT)
+VBoxNetFlt_SOURCES.darwin = darwin/VBoxNetFlt-darwin.cpp
+VBoxNetFlt_SOURCES.win = \
+ win/VBoxNetFlt-win.c \
+ win/VBoxNetFltPt-win.c \
+ win/VBoxNetFlt-win.rc
+ifdef VBOX_NETFLT_ONDEMAND_BIND
+ VBoxNetFlt_DEFS.win += VBOX_NETFLT_ONDEMAND_BIND
+else
+ VBoxNetFlt_DEFS.win += VBOXNETFLT_STATIC_CONFIG
+ VBoxNetFlt_SOURCES.win += win/VBoxNetFltMp-win.c
+endif
+VBoxNetFlt_SOURCES = VBoxNetFlt.c
+VBoxNetFlt_LDFLAGS.darwin = -v -Wl,-whyload -Wl,-v -Wl,-whatsloaded
+VBoxNetFlt_LDFLAGS.win.x86 = -Entry:DriverEntry@8
+VBoxNetFlt_LDFLAGS.win.amd64 = -Entry:DriverEntry
+VBoxNetFlt_SOURCES.win.amd64 += win/VBoxNetFltA-win.asm
+VBoxNetFlt_DEFS.win.amd64 += RT_WITH_W64_UNWIND_HACK
+VBoxNetFlt_LIBS.win = \
+ $(PATH_SDK_W2K3DDK_LIB)/ntoskrnl.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/hal.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/ndis.lib \
+ $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+VBoxNetFlt_LIBS = \
+ $(PATH_LIB)/SUPR0IdcClient$(VBOX_SUFF_LIB)
+
+
+# Darwin extras.
+ifeq ($(KBUILD_TARGET),darwin)
+INSTALLS += VBoxNetFlt.kext
+VBoxNetFlt.kext_INST = $(INST_VBOXNETFLT)Contents/
+VBoxNetFlt.kext_SOURCES = \
+ $(PATH_VBoxNetFlt.kext)/Info.plist
+VBoxNetFlt.kext_CLEAN = \
+ $(PATH_VBoxNetFlt.kext)/Info.plist
+
+$$(PATH_VBoxNetFlt.kext)/Info.plist: $(PATH_SUB_CURRENT)/darwin/Info.plist $(VBOX_VERSION_MK) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxNetFlt,$@,$<)
+ $(xQUIET)$(RM) -f $@
+ $(xQUIET)$(SED) \
+ -e 's/@VBOX_VERSION_STRING@/$(VBOX_VERSION_STRING)/g' \
+ -e 's/@VBOX_VERSION_MAJOR@/$(VBOX_VERSION_MAJOR)/g' \
+ -e 's/@VBOX_VERSION_MINOR@/$(VBOX_VERSION_MINOR)/g' \
+ -e 's/@VBOX_VERSION_BUILD@/$(VBOX_VERSION_BUILD)/g' \
+ --output $@ \
+ $<
+
+INSTALLS.darwin += Scripts-darwin
+Scripts-darwin_INST = $(INST_DIST)
+Scripts-darwin_SOURCES = \
+ darwin/loadnetflt.sh
+endif # darwin
+
+
+ifeq ($(KBUILD_TARGET),win)
+#
+# Windows extras.
+#
+INSTALLS.win += VBoxNetFlt-inf
+VBoxNetFlt-inf_INST = $(INST_BIN)
+VBoxNetFlt-inf_MODE = a+r,u+w
+VBoxNetFlt-inf_SOURCES = \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.inf \
+ $(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt_m.inf
+VBoxNetFlt-inf_CLEAN = $(VBoxNetFlt-inf_SOURCES)
+VBoxNetFlt-inf_BLDDIRS = $(PATH_TARGET)/VBoxNetFltCat.dir $(PATH_TARGET)/VBoxNetFltMpCat.dir
+
+$(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.inf: $(PATH_SUB_CURRENT)/win/VBoxNetFlt.inf $(MAKEFILE_CURRENT) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxNetFlt-inf,$@,$<)
+ $(call VBOX_EDIT_INF_FN,$<,$@)
+
+$(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt_m.inf: $(PATH_SUB_CURRENT)/win/VBoxNetFlt_m.inf $(MAKEFILE_CURRENT) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxNetFlt-inf,$@,$<)
+ $(call VBOX_EDIT_INF_FN,$<,$@)
+
+ ifdef VBOX_SIGNING_MODE
+VBoxNetFlt-inf_SOURCES += \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.sys \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.cat \
+ $(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt_m.cat
+
+$(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.sys: $$(TARGET_VBoxNetFlt) | $$(dir $$@)
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt.sys: $$(TARGET_VBoxNetFlt) | $$(dir $$@)
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFltNotify.dll: $$(TARGET_VBoxNetFltNotify) | $$(dir $$@)
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.cat: \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.sys \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFltNotify.dll \
+ $(PATH_TARGET)/VBoxNetFltCat.dir/VBoxNetFlt.inf
+ $(call MSG_TOOL,Inf2Cat,VBoxNetFlt-inf,$@,$<)
+ $(call VBOX_MAKE_CAT_FN, $(@D),$@)
+
+$(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt_m.cat: \
+ $(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt.sys \
+ $(PATH_TARGET)/VBoxNetFltMpCat.dir/VBoxNetFlt_m.inf
+ $(call MSG_TOOL,Inf2Cat,VBoxNetFlt-inf,$@,$<)
+ $(call VBOX_MAKE_CAT_FN, $(@D),$@)
+
+ endif # signing
+
+#
+# WinNetConfig - static library with host network interface config API
+#
+LIBRARIES.win += WinNetConfig
+WinNetConfig_TEMPLATE = VBOXR3STATIC
+WinNetConfig_DEFS = _WIN32_WINNT=0x0501 _UNICODE UNICODE
+WinNetConfig_SDKS = WINPSDK W2K3DDK
+WinNetConfig_SOURCES = \
+ win/WinNetConfig.cpp
+
+#
+# NetFltInstall
+#
+PROGRAMS.win += NetFltInstall
+NetFltInstall_TEMPLATE = VBOXR3STATIC
+NetFltInstall_SDKS = WINPSDK W2K3DDK VBOX_NTDLL
+NetFltInstall_SOURCES = win/NetFltInstall.cpp
+NetFltInstall_LIBS = $(TARGET_WinNetConfig)
+
+
+#
+# NetFltUninstall
+#
+PROGRAMS.win += NetFltUninstall
+NetFltUninstall_TEMPLATE = VBOXR3STATIC
+NetFltUninstall_SDKS = WINPSDK W2K3DDK VBOX_NTDLL
+NetFltUninstall_SOURCES = win/NetFltUninstall.cpp
+NetFltUninstall_LIBS = $(TARGET_WinNetConfig)
+
+
+#
+# VBoxNetFltNotify
+#
+DLLS.win += VBoxNetFltNotify
+VBoxNetFltNotify_TEMPLATE = VBOXR3STATIC
+VBoxNetFltNotify_SDKS = WINPSDK W2K3DDK VBOX_NTDLL
+VBoxNetFltNotify_DEFS = _WIN32_WINNT=0x0500 WIN32 _ATL_STATIC_REGISTRY
+VBoxNetFltNotify_INCS = \
+ $(PATH_VBoxNetFltNotify)
+VBoxNetFltNotify_SOURCES = \
+ win/notifyobj/VBoxNetFltNotify.cpp \
+ win/notifyobj/VBoxNetFltNotify.def \
+ win/notifyobj/VBoxNetFltNotify.rc
+VBoxNetFltNotify_LIBS = \
+ $(PATH_TOOL_$(VBOX_VCC_TOOL)_ATLMFC_LIB)/atls.lib
+#VBoxNetFltNotify_INTERMEDIATES =
+VBoxNetFltNotify_DEPS = \
+ $(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn_i.c \
+ $(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn_p.c \
+ $(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn.h \
+ $(PATH_VBoxNetFltNotify)/dlldata.c \
+ $(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn.tlb
+VBoxNetFltNotify_CLEAN = $(VBoxNetFltNotify_DEPS)
+
+VBOXNETFLT_NOTIFY_IDL ?= $(EXEC_X86_WIN32) $(call VBOX_FN_MAKE_WIN_PATH,$(firstword $(wildcard \
+ $(PATH_SDK_WINPSDK_BIN)/Midl.Exe\
+ $(PATH_SDK_WINPSDK)/Bin/Midl.Exe\
+ $(PATH_DEVTOOLS)/win.x86/bin/midl.exe\
+ ) Sorry_Cannot_Find_The_Midl_Compiler_In_The_PSDK))
+
+$$(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn_i.c \
++ $$(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn_p.c \
++ $$(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn.h \
++ $$(PATH_VBoxNetFltNotify)/dlldata.c \
++ $$(PATH_VBoxNetFltNotify)/VBoxNetFltNotifyn.tlb: \
+ $(PATH_SUB_CURRENT)/win/notifyobj/VBoxNetFltNotifyn.idl \
+ | $$(dir $$@)
+ $(VBOXNETFLT_NOTIFY_IDL) /nologo \
+ /out $(call VBOX_FN_MAKE_WIN_PATH,$(PATH_VBoxNetFltNotify)) \
+ /cpp_cmd $(subst $(EXEC_X86_WIN32),,$(call VBOX_FN_MAKE_WIN_PATH,$(TOOL_$(VBOX_VCC_TOOL)_CC))) \
+ $(addprefix /I , $(call VBOX_FN_MAKE_WIN_PATH,$(SDK_W2K3DDK_INCS))) \
+ $(call VBOX_FN_MAKE_WIN_PATH,$<)
+endif #ifeq ($(KBUILD_TARGET), win)
+
+else if1of ($(KBUILD_TARGET), linux solaris) ## @todo merge this with the mixed case stuff.
+#
+# vboxnetflt(.ko/.o/) - The lower case driver.
+# Note! On Solaris the name has to be <= 8 chars long.
+#
+ ifdef VBOX_WITH_VBOXDRV
+SYSMODS += vboxnetflt
+vboxnetflt_TEMPLATE = VBOXR0DRV
+vboxnetflt_NAME.solaris = vboxflt
+vboxnetflt_DEFS.linux = KBUILD_MODNAME=KBUILD_STR\(vboxnetflt\) KBUILD_BASENAME=KBUILD_STR\(vboxnetflt\) MODULE
+vboxnetflt_DEFS = IN_RT_R0
+vboxnetflt_DEFS.solaris += VBOX_SVN_REV=$(VBOX_SVN_REV)
+vboxnetflt_DEPS.solaris += $(VBOX_SVN_REV_KMK)
+vboxnetflt_NOINST.linux = true
+vboxnetflt_INCS.linux := \
+ $(PATH_ROOT)/src/VBox/Runtime/r0drv/linux
+vboxnetflt_INCS := \
+ $(PATH_SUB_CURRENT)
+vboxnetflt_LDFLAGS.solaris += -N drv/vboxdrv
+ifdef VBOXNETFLT_SOLARIS_USE_NETINFO
+ vboxnetflt_DEFS.solaris += VBOXNETFLT_SOLARIS_USE_NETINFO
+ vboxnetflt_LDFLAGS.solaris += -N misc/neti
+endif
+vboxnetflt_LIBS = \
+ $(PATH_LIB)/SUPR0IdcClient$(VBOX_SUFF_LIB)
+## @todo vboxflt should resolves all the IPRT bits from vboxdrv.
+#vboxnetflt_LIBS += \
+# $(PATH_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+vboxnetflt_SOURCES.linux = linux/VBoxNetFlt-linux.c
+vboxnetflt_SOURCES.solaris = solaris/VBoxNetFlt-solaris.c
+vboxnetflt_SOURCES = VBoxNetFlt.c
+ endif
+
+endif
+
+ifeq ($(KBUILD_TARGET),linux)
+ #
+ # Install source files for compliation on Linux.
+ # files_vboxnetflt defines VBOX_VBOXNETFLT_SOURCES.
+ #
+ include $(PATH_SUB_CURRENT)/linux/files_vboxnetflt
+ INSTALLS += VBoxNetFlt-src VBoxNetFlt-sh
+ VBoxNetFlt-src_INST = bin/src/vboxnetflt/
+ VBoxNetFlt-src_MODE = a+r,u+w
+ VBoxNetFlt-src_SOURCES = $(subst ",,$(VBOX_VBOXNETFLT_SOURCES)) #"
+ VBoxNetFlt-src_SOURCES+= \
+ $(if $(VBOX_OSE),,\
+ $(PATH_VBoxNetFlt-src)/dkms.conf) \
+ $(PATH_VBoxNetFlt-src)/Makefile
+ VBoxNetFlt-src_CLEAN = \
+ $(PATH_VBoxNetFlt-src)/dkms.conf \
+ $(PATH_VBoxNetFlt-src)/Makefile \
+ $(PATH_TARGET)/VBoxNetFlt-src-1.dep
+
+ VBoxNetFlt-sh_INST = bin/src/vboxnetflt/
+ VBoxNetFlt-sh_MODE = a+rx,u+w
+ VBoxNetFlt-sh_SOURCES = \
+ $(PATH_VBoxNetFlt-sh)/build_in_tmp \
+ $(if $(VBOX_OSE),,\
+ $(PATH_ROOT)/src/VBox/HostDrivers/linux/do_Module.symvers)
+ VBoxNetFlt-sh_CLEAN = $(PATH_VBoxNetFlt-sh)/build_in_tmp
+
+
+includedep $(PATH_TARGET)/VBoxNetFlt-src-1.dep
+$$(PATH_VBoxNetFlt-src)/Makefile: \
+ $(PATH_SUB_CURRENT)/linux/Makefile \
+ $$(if $$(eq $$(VBoxNetFlt/linux/Makefile_VBOX_HARDENED),$$(VBOX_WITH_HARDENING)),,FORCE) \
+ | $$(dir $$@)
+ifndef VBOX_WITH_HARDENING
+ $(QUIET)$(SED) -e "s;-DVBOX_WITH_HARDENING;;g" --output $@ $<
+else
+ $(QUIET)$(CP) -f $< $@
+endif
+ %$(QUIET2)$(RM) -f -- $(PATH_TARGET)/VBoxNetFlt-src-1.dep
+ %$(QUIET2)$(APPEND) '$(PATH_TARGET)/VBoxNetFlt-src-1.dep' 'VBoxNetFlt/linux/Makefile_VBOX_HARDENED=$(VBOX_WITH_HARDENING)'
+
+## Scripts needed for building the kernel modules
+
+$$(PATH_VBoxNetFlt-sh)/build_in_tmp: \
+ $(PATH_ROOT)/src/VBox/HostDrivers/linux/build_in_tmp \
+ $(VBOX_VERSION_STAMP) \
+ | $$(dir $$@)
+ $(call MSG_TOOL,Creating,,$@)
+ $(QUIET)$(SED) -e "s;_VERSION_;${VBOX_VERSION_STRING};g; s;_MODULE_;vboxnetflt;g" --output $@ $<
+ $(QUIET)chmod 0755 $@
+
+$$(PATH_VBoxNetFlt-src)/dkms.conf: \
+ $(PATH_SUB_CURRENT)/linux/dkms.conf \
+ $(VBOX_VERSION_STAMP) \
+ | $$(dir $$@)
+ $(call MSG_TOOL,Creating,,$@)
+ $(QUIET)$(SED) -e "s;_VERSION_;${VBOX_VERSION_STRING};g" --output $@ $<
+
+endif # linux
+
+include $(KBUILD_PATH)/subfooter.kmk
+
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
new file mode 100644
index 000000000..ca26bcf1f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
@@ -0,0 +1,1341 @@
+/* $Id: VBoxNetFlt.c 15950 2009-01-14 18:25:22Z vboxsync $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Common Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/** @page pg_netflt VBoxNetFlt - Network Interface Filter
+ *
+ * This is a kernel module that attaches to a real interface on the host
+ * and filters and injects packets.
+ *
+ * In the big picture we're one of the three trunk interface on the internal
+ * network, the one named "NIC Filter Driver": @image html Networking_Overview.gif
+ *
+ *
+ * @section sec_netflt_msc Locking / Sequence Diagrams
+ *
+ * This secion contains a few sequence diagrams describing the problematic
+ * transitions of a host interface filter instance.
+ *
+ * The thing that makes it all a bit problematic is that multiple events may
+ * happen at the same time, and that we have to be very careful to avoid
+ * deadlocks caused by mixing our locks with the ones in the host kernel.
+ * The main events are receive, send, async send completion, disappearance of
+ * the host networking interface and it's reappearance. The latter two events
+ * are can be caused by driver unloading/loading or the device being physical
+ * unplugged (e.g. a USB network device).
+ *
+ * The strategy for dealing with these issues are:
+ * - Use a simple state machine.
+ * - Require the user (IntNet) to serialize all its calls to us,
+ * while at the same time not owning any lock used by any of the
+ * the callbacks we might call on receive and async send completion.
+ * - Make sure we're 100% idle before disconnecting, and have a
+ * disconnected status on both sides to fend off async calls.
+ * - Protect the host specific interface handle and the state variables
+ * using a spinlock.
+ *
+ *
+ * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release
+ *
+ * @msc
+ * VM, IntNet, NetFlt, Kernel, Wire;
+ *
+ * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
+ * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
+ * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
+ * NetFlt=>Kernel [label="pkt0 to wire", linecolor="green", textcolor="green"];
+ * Kernel->Wire [label="pkt0 to wire", linecolor="green", textcolor="green"];
+ *
+ * --- [label="Suspending the trunk interface"];
+ * IntNet=>IntNet [label="Lock Network"];
+ *
+ * Wire->Kernel [label="pkt1 - racing us", linecolor="red", textcolor="red"];
+ * Kernel=>>NetFlt [label="pkt1 - racing us", linecolor="red", textcolor="red"];
+ * NetFlt=>>IntNet [label="pkt1 recv - blocks", linecolor="red", textcolor="red"];
+ *
+ * IntNet=>IntNet [label="Mark Trunk Suspended"];
+ * IntNet=>IntNet [label="Unlock Network"];
+ *
+ * IntNet=>NetFlt [label="pfnSetActive(false)"];
+ * NetFlt=>NetFlt [label="Mark inactive (atomic)"];
+ * IntNet<<NetFlt;
+ * IntNet=>NetFlt [label="pfnWaitForIdle(forever)"];
+ *
+ * IntNet=>>NetFlt [label="pkt1 to host", linecolor="red", textcolor="red"];
+ * NetFlt=>>Kernel [label="pkt1 to host", linecolor="red", textcolor="red"];
+ *
+ * Kernel<-Wire [label="pkt0 on wire", linecolor="green", textcolor="green"];
+ * NetFlt<<Kernel [label="pkt0 on wire", linecolor="green", textcolor="green"];
+ * IntNet<<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
+ * IntNet<<=IntNet [label="Lock Net, free SG, Unlock Net", linecolor="green", textcolor="green"];
+ * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
+ * NetFlt<-NetFlt [label="idle", linecolor="green", textcolor="green"];
+ *
+ * IntNet<<NetFlt [label="idle (pfnWaitForIdle)"];
+ *
+ * Wire->Kernel [label="pkt2", linecolor="red", textcolor="red"];
+ * Kernel=>>NetFlt [label="pkt2", linecolor="red", textcolor="red"];
+ * NetFlt=>>Kernel [label="pkt2 to host", linecolor="red", textcolor="red"];
+ *
+ * VM->IntNet [label="pkt3", linecolor="green", textcolor="green"];
+ * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Route packet -> drop", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
+ *
+ * --- [label="The trunk interface is idle now, disconnect it"];
+ * IntNet=>IntNet [label="Lock Network"];
+ * IntNet=>IntNet [label="Unlink Trunk"];
+ * IntNet=>IntNet [label="Unlock Network"];
+ * IntNet=>NetFlt [label="pfnDisconnectAndRelease"];
+ * NetFlt=>Kernel [label="iflt_detach"];
+ * NetFlt<<=Kernel [label="iff_detached"];
+ * NetFlt>>Kernel [label="iff_detached"];
+ * NetFlt<<Kernel [label="iflt_detach"];
+ * NetFlt=>NetFlt [label="Release"];
+ * IntNet<<NetFlt [label="pfnDisconnectAndRelease"];
+ *
+ * @endmsc
+ *
+ *
+ *
+ * @subsection subsec_netflt_msc_hif_rm Host Interface Removal
+ *
+ * The ifnet_t (pIf) is a tricky customer as any reference to it can potentially
+ * race the filter detaching. The simple way of solving it on Darwin is to guard
+ * all access to the pIf member with a spinlock. The other host systems will
+ * probably have similar race conditions, so the spinlock is a generic thing.
+ *
+ * @msc
+ * VM, IntNet, NetFlt, Kernel;
+ *
+ * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
+ * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
+ * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
+ * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
+ * NetFlt=>Kernel [label="ifnet_reference w/ spinlock", linecolor="green", textcolor="green" ];
+ * NetFlt<<Kernel [label="ifnet_reference", linecolor="green", textcolor="green" ];
+ * NetFlt=>Kernel [label="pkt0 to wire (blocks)", linecolor="green", textcolor="green" ];
+ *
+ * --- [label="The host interface is being disconnected"];
+ * Kernel->NetFlt [label="iff_detached"];
+ * NetFlt=>Kernel [label="ifnet_release w/ spinlock"];
+ * NetFlt<<Kernel [label="ifnet_release"];
+ * NetFlt=>NetFlt [label="fDisconnectedFromHost=true"];
+ * NetFlt>>Kernel [label="iff_detached"];
+ *
+ * NetFlt<<Kernel [label="dropped", linecolor="green", textcolor="green"];
+ * NetFlt=>NetFlt [label="Acquire spinlock", linecolor="green", textcolor="green"];
+ * NetFlt=>Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
+ * NetFlt<<Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
+ * NetFlt=>NetFlt [label="pIf=NULL", linecolor="green", textcolor="green"];
+ * NetFlt=>NetFlt [label="Release spinlock", linecolor="green", textcolor="green"];
+ * IntNet<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
+ * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
+ * IntNet<<NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green"];
+ *
+ * @endmsc
+ *
+ *
+ *
+ * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery
+ *
+ * The rediscovery is performed when we receive a send request and a certain
+ * period have elapsed since the last attempt, i.e. we're polling it. We
+ * synchronize the rediscovery with disconnection from the internal network
+ * by means of the pfnWaitForIdle call, so no special handling is required.
+ *
+ * @msc
+ * VM2, VM1, IntNet, NetFlt, Kernel, Wire;
+ *
+ * --- [label="Rediscovery conditions are not met"];
+ * VM1->IntNet [label="pkt0"];
+ * IntNet=>IntNet [label="Lock Network"];
+ * IntNet=>IntNet [label="Route packet -> wire"];
+ * IntNet=>IntNet [label="Unlock Network"];
+ * IntNet=>NetFlt [label="pkt0 to wire"];
+ * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
+ * IntNet<<NetFlt [label="pkt0 to wire (dropped)"];
+ *
+ * --- [label="Rediscovery conditions"];
+ * VM1->IntNet [label="pkt1"];
+ * IntNet=>IntNet [label="Lock Network"];
+ * IntNet=>IntNet [label="Route packet -> wire"];
+ * IntNet=>IntNet [label="Unlock Network"];
+ * IntNet=>NetFlt [label="pkt1 to wire"];
+ * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
+ * NetFlt=>NetFlt [label="fRediscoveryPending=true w/ spinlock"];
+ * NetFlt=>Kernel [label="ifnet_find_by_name"];
+ * NetFlt<<Kernel [label="ifnet_find_by_name (success)"];
+ *
+ * VM2->IntNet [label="pkt2", linecolor="red", textcolor="red"];
+ * IntNet=>IntNet [label="Lock Network", linecolor="red", textcolor="red"];
+ * IntNet=>IntNet [label="Route packet -> wire", linecolor="red", textcolor="red"];
+ * IntNet=>IntNet [label="Unlock Network", linecolor="red", textcolor="red"];
+ * IntNet=>NetFlt [label="pkt2 to wire", linecolor="red", textcolor="red"];
+ * NetFlt=>NetFlt [label="!pIf || fRediscoveryPending (w/ spinlock)", linecolor="red", textcolor="red"];
+ * IntNet<<NetFlt [label="pkt2 to wire (dropped)", linecolor="red", textcolor="red"];
+
+ * NetFlt=>Kernel [label="iflt_attach"];
+ * NetFlt<<Kernel [label="iflt_attach (success)"];
+ * NetFlt=>NetFlt [label="Acquire spinlock"];
+ * NetFlt=>NetFlt [label="Set pIf and update flags"];
+ * NetFlt=>NetFlt [label="Release spinlock"];
+ *
+ * NetFlt=>Kernel [label="pkt1 to wire"];
+ * Kernel->Wire [label="pkt1 to wire"];
+ * NetFlt<<Kernel [label="pkt1 to wire"];
+ * IntNet<<NetFlt [label="pkt1 to wire"];
+ *
+ *
+ * @endmsc
+ *
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+#include "VBoxNetFltInternal.h"
+
+#include <VBox/sup.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/time.h>
+#include <iprt/uuid.h>
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define IFPORT_2_VBOXNETFLTINS(pIfPort) \
+ ( (PVBOXNETFLTINS)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETFLTINS, MyPort)) )
+
+
+/**
+ * Finds a instance by its name, the caller does the locking.
+ *
+ *
+ * @returns Pointer to the instance by the given name. NULL if not found.
+ * @param pGlobals The globals.
+ * @param pszName The name of the instance.
+ */
+static PVBOXNETFLTINS vboxNetFltFindInstanceLocked(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
+{
+ PVBOXNETFLTINS pCur;
+ for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
+ if (!strcmp(pszName, pCur->szName))
+ return pCur;
+ return NULL;
+}
+
+
+/**
+ * Finds a instance by its name, will request the mutex.
+ *
+ * @returns Pointer to the instance by the given name. NULL if not found.
+ * @param pGlobals The globals.
+ * @param pszName The name of the instance.
+ */
+DECLHIDDEN(PVBOXNETFLTINS) vboxNetFltFindInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
+{
+ PVBOXNETFLTINS pRet;
+ int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ AssertRCReturn(rc, NULL);
+
+ pRet = vboxNetFltFindInstanceLocked(pGlobals, pszName);
+
+ rc = RTSemFastMutexRelease(pGlobals->hFastMtx);
+ AssertRC(rc);
+ return pRet;
+}
+
+
+/**
+ * Unlinks an instance from the chain.
+ *
+ * @param pGlobals The globals.
+ * @param pToUnlink The instance to unlink.
+ */
+static void vboxNetFltUnlinkLocked(PVBOXNETFLTGLOBALS pGlobals, PVBOXNETFLTINS pToUnlink)
+{
+ if (pGlobals->pInstanceHead == pToUnlink)
+ pGlobals->pInstanceHead = pToUnlink->pNext;
+ else
+ {
+ PVBOXNETFLTINS pCur;
+ for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
+ if (pCur->pNext == pToUnlink)
+ {
+ pCur->pNext = pToUnlink->pNext;
+ break;
+ }
+ Assert(pCur);
+ }
+ pToUnlink->pNext = NULL;
+}
+
+
+AssertCompileMemberSize(VBOXNETFLTINS, enmState, sizeof(uint32_t));
+
+/**
+ * Sets the enmState member atomically.
+ *
+ * Used for all updates.
+ *
+ * @param pThis The instance.
+ * @param enmNewState The new value.
+ */
+DECLINLINE(void) vboxNetFltSetState(PVBOXNETFLTINS pThis, VBOXNETFTLINSSTATE enmNewState)
+{
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
+}
+
+
+/**
+ * Gets the enmState member atomically.
+ *
+ * Used for all reads.
+ *
+ * @returns The enmState value.
+ * @param pThis The instance.
+ */
+DECLINLINE(VBOXNETFTLINSSTATE) vboxNetFltGetState(PVBOXNETFLTINS pThis)
+{
+ return (VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
+}
+
+
+/**
+ * Performs interface rediscovery if it was disconnected from the host.
+ *
+ * @returns true if successfully rediscovered and connected, false if not.
+ * @param pThis The instance.
+ */
+static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ uint64_t Now = RTTimeNanoTS();
+ bool fRediscovered;
+ bool fDoIt;
+
+ /*
+ * Rediscovered already? Time to try again?
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+
+ fRediscovered = !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+ fDoIt = !fRediscovered
+ && !ASMAtomicUoReadBool(&pThis->fRediscoveryPending)
+ && Now - ASMAtomicUoReadU64(&pThis->NanoTSLastRediscovery) > UINT64_C(5000000000); /* 5 sec */
+ if (fDoIt)
+ ASMAtomicWriteBool(&pThis->fRediscoveryPending, true);
+
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ /*
+ * Call the OS specific code to do the job.
+ * Update the state when the call returns, that is everything except for
+ * the fDisconnectedFromHost flag which the OS specific code shall set.
+ */
+ if (fDoIt)
+ {
+ fRediscovered = vboxNetFltOsMaybeRediscovered(pThis);
+
+ Assert(!fRediscovered || !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost));
+
+ ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, RTTimeNanoTS());
+ ASMAtomicWriteBool(&pThis->fRediscoveryPending, false);
+
+ if (fRediscovered)
+ vboxNetFltPortOsSetActive(pThis, pThis->fActive);
+ }
+
+ return fRediscovered;
+}
+
+#ifdef RT_WITH_W64_UNWIND_HACK
+# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
+# define NETFLT_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
+# define NETFLT_CALLBACK(_n) netfltNtWrap##_n
+
+NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
+NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
+NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
+NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
+NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
+NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
+NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
+NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRetain)(PINTNETTRUNKIFPORT pIfPort);
+NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRelease)(PINTNETTRUNKIFPORT pIfPort);
+
+# else
+# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
+# endif
+#else
+# define NETFLT_DECL_CALLBACK(type) static DECLCALLBACK(type)
+# define NETFLT_CALLBACK(_n) _n
+#endif
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnXmit
+ */
+NETFLT_DECL_CALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ int rc = VINF_SUCCESS;
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pSG);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
+ Assert(pThis->fActive);
+
+ /*
+ * Do a busy retain and then make sure we're connected to the interface
+ * before invoking the OS specific code.
+ */
+ vboxNetFltRetain(pThis, true /* fBusy */);
+ if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
+ || vboxNetFltMaybeRediscovered(pThis))
+ rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
+ vboxNetFltRelease(pThis, true /* fBusy */);
+
+ return rc;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
+ */
+NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
+ Assert(pThis->fActive);
+
+ /*
+ * Ask the OS specific code.
+ */
+ return vboxNetFltPortOsIsPromiscuous(pThis);
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
+ */
+NETFLT_DECL_CALLBACK(void) vboxNetFltPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
+ Assert(pThis->fActive);
+
+ /*
+ * Forward the question to the OS specific code.
+ */
+ vboxNetFltPortOsGetMacAddress(pThis, pMac);
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
+ */
+NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
+ Assert(pThis->fActive);
+
+ /*
+ * Ask the OS specific code.
+ */
+ return vboxNetFltPortOsIsHostMac(pThis, pMac);
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
+ */
+NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ int rc;
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
+ AssertReturn(!pThis->fActive, VERR_INVALID_STATE);
+
+ /*
+ * Go to sleep on the semaphore after checking the busy count.
+ */
+ vboxNetFltRetain(pThis, false /* fBusy */);
+
+ rc = VINF_SUCCESS;
+ while (pThis->cBusy && RT_SUCCESS(rc))
+ rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
+
+ vboxNetFltRelease(pThis, false /* fBusy */);
+
+ return rc;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnSetActive
+ */
+NETFLT_DECL_CALLBACK(bool) vboxNetFltPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, false);
+
+ /*
+ * We're assuming that the caller is serializing the calls, so we don't
+ * have to be extremely careful here. Just update first and then call
+ * the OS specific code, the update must be serialized for various reasons.
+ */
+ if (ASMAtomicReadBool(&pThis->fActive) != fActive)
+ {
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ ASMAtomicWriteBool(&pThis->fActive, fActive);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ vboxNetFltPortOsSetActive(pThis, fActive);
+ }
+ else
+ fActive = !fActive;
+ return !fActive;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
+ */
+NETFLT_DECL_CALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+ /*
+ * Serious paranoia.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
+ Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
+ Assert(pThis->szName[0]);
+
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
+ Assert(!pThis->fActive);
+ Assert(!pThis->fRediscoveryPending);
+ Assert(!pThis->cBusy);
+
+ /*
+ * Disconnect and release it.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ vboxNetFltOsDisconnectIt(pThis);
+ pThis->pSwitchPort = NULL;
+
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ vboxNetFltSetState(pThis, kVBoxNetFltInsState_Unconnected);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+#endif
+
+ vboxNetFltRelease(pThis, false /* fBusy */);
+}
+
+
+/**
+ * Destroy a device that has been disconnected from the switch.
+ *
+ * @return true iff the instance is destroyed, false otherwise
+ * @param pThis The instance to be destroyed. This is
+ * no longer valid when this function returns.
+ */
+static bool vboxNetFltCheckDestroyInstance(PVBOXNETFLTINS pThis)
+{
+ PVBOXNETFLTGLOBALS pGlobals = pThis->pGlobals;
+ int rc;
+ uint32_t cRefs = ASMAtomicUoReadU32((uint32_t volatile *)&pThis->cRefs);
+ LogFlow(("vboxNetFltCheckDestroyInstance: pThis=%p (%s)\n", pThis, pThis->szName));
+
+ /*
+ * Validate the state.
+ */
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ Assert( vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting
+ || vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
+#else
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting);
+#endif
+ Assert(!pThis->fActive);
+ Assert(!pThis->fRediscoveryPending);
+ Assert(!pThis->cRefs);
+ Assert(!pThis->cBusy);
+ Assert(!pThis->pSwitchPort);
+
+ /*
+ * Make sure the state is 'disconnecting' and let the OS specific code
+ * do its part of the cleanup outside the mutex.
+ */
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
+ if(cRefs != 0)
+ {
+ Assert(cRefs < UINT32_MAX / 2);
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ return false;
+ }
+ vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroying);
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+ vboxNetFltOsDeleteInstance(pThis);
+
+ /*
+ * Unlink the instance and free up its resources.
+ */
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
+ vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroyed);
+ vboxNetFltUnlinkLocked(pGlobals, pThis);
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+ RTSemEventDestroy(pThis->hEventIdle);
+ pThis->hEventIdle = NIL_RTSEMEVENT;
+ RTSpinlockDestroy(pThis->hSpinlock);
+ pThis->hSpinlock = NIL_RTSPINLOCK;
+ RTMemFree(pThis);
+ return true;
+}
+
+
+/**
+ * Releases a reference to the specified instance.
+ *
+ * This method will destroy the instance when the count reaches 0.
+ * It will also take care of decrementing the counter and idle wakeup.
+ *
+ * @param pThis The instance.
+ * @param fBusy Whether the busy counter should be decremented too.
+ */
+DECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy)
+{
+ uint32_t cRefs;
+
+ /*
+ * Paranoid Android.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
+ && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
+ Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
+ Assert(pThis->szName[0]);
+
+ /*
+ * Work the busy counter.
+ */
+ if (fBusy)
+ {
+ cRefs = ASMAtomicDecU32(&pThis->cBusy);
+ if (!cRefs)
+ {
+ int rc = RTSemEventSignal(pThis->hEventIdle);
+ AssertRC(rc);
+ }
+ else
+ Assert(cRefs < UINT32_MAX / 2);
+ }
+
+ /*
+ * The object reference counting.
+ */
+ cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ if (!cRefs)
+ vboxNetFltCheckDestroyInstance(pThis);
+ else
+ Assert(cRefs < UINT32_MAX / 2);
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRetain
+ */
+NETFLT_DECL_CALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ vboxNetFltRelease(pThis, false /* fBusy */);
+}
+
+
+/**
+ * Retains a reference to the specified instance and a busy reference too.
+ *
+ * @param pThis The instance.
+ * @param fBusy Whether the busy counter should be incremented as well.
+ */
+DECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy)
+{
+ uint32_t cRefs;
+
+ /*
+ * Paranoid Android.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
+ && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
+ Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
+ Assert(pThis->szName[0]);
+
+ /*
+ * Retain the object.
+ */
+ cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
+
+ /*
+ * Work the busy counter.
+ */
+ if (fBusy)
+ {
+ cRefs = ASMAtomicIncU32(&pThis->cBusy);
+ Assert(cRefs > 0 && cRefs < UINT32_MAX / 2);
+ }
+
+ NOREF(cRefs);
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRetain
+ */
+NETFLT_DECL_CALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ vboxNetFltRetain(pThis, false /* fBusy */);
+}
+
+
+/**
+ * Connects the instance to the specified switch port.
+ *
+ * Called while owning the lock. We're ASSUMING that the internal
+ * networking code is already owning an recursive mutex, so, there
+ * will be no deadlocks when vboxNetFltOsConnectIt calls back into
+ * it for setting preferences.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param pSwitchPort The port on the internal network 'switch'.
+ * @param ppIfPort Where to return our port interface.
+ */
+static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
+{
+ int rc;
+
+ /*
+ * Validate state.
+ */
+ Assert(!pThis->fActive);
+ Assert(!pThis->fRediscoveryPending);
+ Assert(!pThis->cBusy);
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
+#else
+ Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Initializing);
+#endif
+
+ /*
+ * Do the job.
+ * Note that we're calling the os stuff while owning the semaphore here.
+ */
+ pThis->pSwitchPort = pSwitchPort;
+ rc = vboxNetFltOsConnectIt(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetFltSetState(pThis, kVBoxNetFltInsState_Connected);
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ *ppIfPort = &pThis->MyPort;
+#endif
+ }
+ else
+ pThis->pSwitchPort = NULL;
+
+ Assert(!pThis->fActive);
+ return rc;
+}
+
+
+/**
+ * Creates a new instance.
+ *
+ * The new instance will be in the suspended state in a dynamic config and in
+ * the inactive in a static one.
+ *
+ * Called without owning the lock, but will request is several times.
+ *
+ * @returns VBox status code.
+ * @param pGlobals The globals.
+ * @param pszName The instance name.
+ * @param pSwitchPort The port on the switch that we're connected with (dynamic only).
+ * @param ppIfPort Where to store the pointer to our port interface (dynamic only).
+ */
+static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ , void * pContext
+#endif
+ )
+{
+ /*
+ * Allocate and initialize a new instance before requesting the mutex.
+ */
+ int rc;
+ size_t const cchName = strlen(pszName);
+ PVBOXNETFLTINS pNew = (PVBOXNETFLTINS)RTMemAllocZ(RT_OFFSETOF(VBOXNETFLTINS, szName[cchName + 1]));
+ if (!pNew)
+ return VERR_INTNET_FLT_IF_FAILED;
+ pNew->pNext = NULL;
+ pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
+ pNew->MyPort.pfnRetain = NETFLT_CALLBACK(vboxNetFltPortRetain);
+ pNew->MyPort.pfnRelease = NETFLT_CALLBACK(vboxNetFltPortRelease);
+ pNew->MyPort.pfnDisconnectAndRelease= NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease);
+ pNew->MyPort.pfnSetActive = NETFLT_CALLBACK(vboxNetFltPortSetActive);
+ pNew->MyPort.pfnWaitForIdle = NETFLT_CALLBACK(vboxNetFltPortWaitForIdle);
+ pNew->MyPort.pfnGetMacAddress = NETFLT_CALLBACK(vboxNetFltPortGetMacAddress);
+ pNew->MyPort.pfnIsHostMac = NETFLT_CALLBACK(vboxNetFltPortIsHostMac);
+ pNew->MyPort.pfnIsPromiscuous = NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous);
+ pNew->MyPort.pfnXmit = NETFLT_CALLBACK(vboxNetFltPortXmit);
+ pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
+ pNew->pSwitchPort = NULL;
+ pNew->pGlobals = pGlobals;
+ pNew->hSpinlock = NIL_RTSPINLOCK;
+ pNew->enmState = kVBoxNetFltInsState_Initializing;
+ pNew->fActive = false;
+ pNew->fDisconnectedFromHost = false;
+ pNew->fRediscoveryPending = false;
+ pNew->NanoTSLastRediscovery = INT64_MAX;
+ pNew->cRefs = 1;
+ pNew->cBusy = 0;
+ pNew->hEventIdle = NIL_RTSEMEVENT;
+ memcpy(pNew->szName, pszName, cchName + 1);
+
+ rc = RTSpinlockCreate(&pNew->hSpinlock);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pNew->hEventIdle);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltOsPreInitInstance(pNew);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Insert the instance into the chain, checking for
+ * duplicates first of course (race).
+ */
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+ if (!vboxNetFltFindInstanceLocked(pGlobals, pszName))
+ {
+ pNew->pNext = pGlobals->pInstanceHead;
+ pGlobals->pInstanceHead = pNew;
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+ /*
+ * Call the OS specific initialization code.
+ */
+ rc = vboxNetFltOsInitInstance(pNew
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ , pContext
+#endif
+ );
+ RTSemFastMutexRequest(pGlobals->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ pNew->enmState = kVBoxNetFltInsState_Unconnected;
+ Assert(!pSwitchPort);
+ *ppIfPort = &pNew->MyPort;
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ return rc;
+
+#else
+ /*
+ * Connect it as well, the OS specific bits has to be done outside
+ * the lock as they may call back to into intnet.
+ */
+ rc = vboxNetFltConnectIt(pNew, pSwitchPort, ppIfPort);
+ if (RT_SUCCESS(rc))
+ {
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ *ppIfPort = &pNew->MyPort;
+ return rc;
+ }
+
+ /* Bail out (failed). */
+ vboxNetFltOsDeleteInstance(pNew);
+#endif
+ }
+ vboxNetFltUnlinkLocked(pGlobals, pNew);
+ }
+ else
+ rc = VERR_INTNET_FLT_IF_BUSY;
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ }
+ }
+ RTSemEventDestroy(pNew->hEventIdle);
+ }
+ RTSpinlockDestroy(pNew->hSpinlock);
+ }
+
+ RTMemFree(pNew);
+ return rc;
+}
+
+#ifdef VBOXNETFLT_STATIC_CONFIG
+
+/**
+ * searches for the NetFlt instance by its name and creates the new one if not found
+ *
+ * @return VINF_SUCCESS if new instance was created, VINF_ALREADY_INITIALIZED if an instanmce already exists,
+ * VERR_xxx in case of a failure
+ */
+DECLHIDDEN(int) vboxNetFltSearchCreateInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PVBOXNETFLTINS *ppInstance, void * pContext)
+{
+ PINTNETTRUNKIFPORT pIfPort;
+ int rc;
+
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ AssertRCReturn(rc, rc);
+
+ *ppInstance = vboxNetFltFindInstanceLocked(pGlobals, pszName);
+ if(*ppInstance)
+ {
+ VBOXNETFTLINSSTATE enmState = vboxNetFltGetState(*ppInstance);
+ if(enmState != kVBoxNetFltInsState_Destroying && enmState != kVBoxNetFltInsState_Destroyed)
+ {
+ vboxNetFltRetain(*ppInstance, false);
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ return VINF_ALREADY_INITIALIZED;
+ }
+
+ /*wait for the instance to be removed from the list */
+
+ *ppInstance = NULL;
+
+ do
+ {
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+ RTSemEventWait(pGlobals->hTimerEvent, 2);
+
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ AssertRCReturn(rc, rc);
+ } while(vboxNetFltFindInstanceLocked(pGlobals, pszName));
+ }
+
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+ rc = vboxNetFltNewInstance(pGlobals, pszName, NULL, &pIfPort, pContext);
+ if(RT_SUCCESS(rc))
+ *ppInstance = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ else
+ *ppInstance = NULL;
+
+ return rc;
+}
+
+#endif
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
+ */
+static DECLCALLBACK(int) vboxNetFltFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
+ PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
+{
+ PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
+ PVBOXNETFLTINS pCur;
+ int rc;
+
+ LogFlow(("vboxNetFltFactoryCreateAndConnect: pszName=%p:{%s}\n", pszName, pszName));
+ Assert(pGlobals->cFactoryRefs > 0);
+
+ /*
+ * Static: Find instance, check if busy, connect if not.
+ * Dynamic: Check for duplicate / busy interface instance.
+ */
+ rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ AssertRCReturn(rc, rc);
+
+ pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
+ if (pCur)
+ {
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ switch (vboxNetFltGetState(pCur))
+ {
+ case kVBoxNetFltInsState_Unconnected:
+ /* instance can be destroyed when it is neither used by the IntNet nor by the ndis filter driver mechanism
+ * (i.e. the driver is not bound to the specified adapter)*/
+ vboxNetFltRetain(pCur, false /* fBusy */); /** @todo who releases this on failure? */
+ rc = vboxNetFltConnectIt(pCur, pSwitchPort, ppIfPort);
+ break;
+ case kVBoxNetFltInsState_Connected:
+ AssertFailed();
+ rc = VERR_INTNET_FLT_IF_BUSY;
+ break;
+ case kVBoxNetFltInsState_Disconnecting:
+ AssertFailed();
+ rc = VERR_INTNET_FLT_IF_BUSY;
+ break;
+ default:
+ /** @todo what? */
+ rc = VERR_INTNET_FLT_IF_BUSY;
+ break;
+ }
+#else
+ rc = VERR_INTNET_FLT_IF_BUSY;
+#endif
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
+ return rc;
+ }
+
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ rc = VERR_INTNET_FLT_IF_NOT_FOUND;
+#else
+ /*
+ * Dynamically create a new instance.
+ */
+ rc = vboxNetFltNewInstance(pGlobals, pszName, pSwitchPort, ppIfPort);
+#endif
+ LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnRelease
+ */
+static DECLCALLBACK(void) vboxNetFltFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
+{
+ PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
+
+ int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
+ Assert(cRefs >= 0); NOREF(cRefs);
+ LogFlow(("vboxNetFltFactoryRelease: cRefs=%d (new)\n", cRefs));
+}
+
+
+/**
+ * Implements the SUPDRV component factor interface query method.
+ *
+ * @returns Pointer to an interface. NULL if not supported.
+ *
+ * @param pSupDrvFactory Pointer to the componet factory registration structure.
+ * @param pSession The session - unused.
+ * @param pszInterfaceUuid The factory interface id.
+ */
+static DECLCALLBACK(void *) vboxNetFltQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
+{
+ PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, SupDrvFactory));
+
+ /*
+ * Convert the UUID strings and compare them.
+ */
+ RTUUID UuidReq;
+ int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
+ if (RT_SUCCESS(rc))
+ {
+ if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
+ {
+ ASMAtomicIncS32(&pGlobals->cFactoryRefs);
+ return &pGlobals->TrunkFactory;
+ }
+#ifdef LOG_ENABLED
+ /* log legacy queries */
+ /* else if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_V1_UUID_STR))
+ Log(("VBoxNetFlt: V1 factory query\n"));
+ */
+ else
+ Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
+#endif
+ }
+ else
+ Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
+
+ return NULL;
+}
+
+
+/**
+ * Checks whether the VBoxNetFlt wossname can be unloaded.
+ *
+ * This will return false if someone is currently using the module.
+ *
+ * @returns true if it's relatively safe to unload it, otherwise false.
+ * @param pGlobals Pointer to the globals.
+ */
+DECLHIDDEN(bool) vboxNetFltCanUnload(PVBOXNETFLTGLOBALS pGlobals)
+{
+ int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ bool fRc = !pGlobals->pInstanceHead
+ && pGlobals->cFactoryRefs <= 0;
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+ AssertRC(rc);
+ return fRc;
+}
+
+/**
+ * tries to deinitialize Idc
+ * we separate the globals settings "base" which is actually
+ * "general" globals settings except for Idc, and idc.
+ * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
+ * thus it's not possible to make idc initialization from the driver startup routine for it,
+ * though the "base is still needed for the driver to functions".
+ * @param pGlobals
+ * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
+ */
+DECLHIDDEN(int) vboxNetFltTryDeleteIdc(PVBOXNETFLTGLOBALS pGlobals)
+{
+ int rc;
+
+ Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
+
+ /*
+ * Check before trying to deregister the factory.
+ */
+ if (!vboxNetFltCanUnload(pGlobals))
+ return VERR_WRONG_ORDER;
+
+ /*
+ * Disconnect from SUPDRV and check that nobody raced us,
+ * reconnect if that should happen.
+ */
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ if (!vboxNetFltCanUnload(pGlobals))
+ {
+ rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ return VERR_WRONG_ORDER;
+ }
+
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+
+ return rc;
+}
+
+/**
+ * performs "base" globals deinitialization
+ * we separate the globals settings "base" which is actually
+ * "general" globals settings except for Idc, and idc.
+ * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
+ * thus it's not possible to make idc initialization from the driver startup routine for it,
+ * though the "base is still needed for the driver to functions".
+ * @param pGlobals
+ * @return none
+ */
+DECLHIDDEN(void) vboxNetFltDeleteGlobalsBase(PVBOXNETFLTGLOBALS pGlobals)
+{
+ /*
+ * Release resources.
+ */
+ RTSemFastMutexDestroy(pGlobals->hFastMtx);
+ pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
+
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ RTSemEventDestroy(pGlobals->hTimerEvent);
+ pGlobals->hTimerEvent = NIL_RTSEMEVENT;
+#endif
+
+}
+
+/**
+ * Called by the native part when the OS wants the driver to unload.
+ *
+ * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
+ *
+ * @param pGlobals Pointer to the globals.
+ */
+DECLHIDDEN(int) vboxNetFltTryDeleteGlobals(PVBOXNETFLTGLOBALS pGlobals)
+{
+ int rc = vboxNetFltTryDeleteIdc(pGlobals);
+ if(RT_SUCCESS(rc))
+ {
+ vboxNetFltDeleteGlobalsBase(pGlobals);
+ }
+ return rc;
+}
+
+/**
+ * performs the "base" globals initialization
+ * we separate the globals initialization to globals "base" initialization which is actually
+ * "general" globals initialization except for Idc not being initialized, and idc initialization.
+ * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
+ * thus it's not possible to make idc initialization from the driver startup routine for it.
+ *
+ * @returns VBox status code.
+ * @param pGlobals Pointer to the globals. */
+DECLHIDDEN(int) vboxNetFltInitGlobalsBase(PVBOXNETFLTGLOBALS pGlobals)
+{
+ /*
+ * Initialize the common portions of the structure.
+ */
+ int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ rc = RTSemEventCreate(&pGlobals->hTimerEvent);
+ if (RT_SUCCESS(rc))
+ {
+#endif
+ pGlobals->pInstanceHead = NULL;
+
+ pGlobals->TrunkFactory.pfnRelease = vboxNetFltFactoryRelease;
+ pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetFltFactoryCreateAndConnect;
+
+ strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetFlt");
+ pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetFltQueryFactoryInterface;
+
+ return rc;
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ }
+ RTSemFastMutexDestroy(pGlobals->hFastMtx);
+#endif
+ }
+
+ return rc;
+}
+
+/**
+ * performs the Idc initialization
+ * we separate the globals initialization to globals "base" initialization which is actually
+ * "general" globals initialization except for Idc not being initialized, and idc initialization.
+ * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
+ * thus it's not possible to make idc initialization from the driver startup routine for it.
+ *
+ * @returns VBox status code.
+ * @param pGlobals Pointer to the globals. */
+DECLHIDDEN(int) vboxNetFltInitIdc(PVBOXNETFLTGLOBALS pGlobals)
+{
+ int rc;
+ /*
+ * Establish a connection to SUPDRV and register our component factory.
+ */
+ rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBoxNetFlt: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
+ return rc;
+ }
+
+ /* bail out. */
+ LogRel(("VBoxNetFlt: Failed to register component factory, rc=%Rrc\n", rc));
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ }
+
+ return rc;
+}
+
+/**
+ * Called by the native driver/kext module initialization routine.
+ *
+ * It will initialize the common parts of the globals, assuming the caller
+ * has already taken care of the OS specific bits.
+ *
+ * @returns VBox status code.
+ * @param pGlobals Pointer to the globals.
+ */
+DECLHIDDEN(int) vboxNetFltInitGlobals(PVBOXNETFLTGLOBALS pGlobals)
+{
+ /*
+ * Initialize the common portions of the structure.
+ */
+ int rc = vboxNetFltInitGlobalsBase(pGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltInitIdc(pGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ return rc;
+ }
+
+ /* bail out. */
+ vboxNetFltDeleteGlobalsBase(pGlobals);
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
new file mode 100644
index 000000000..56d3aac33
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
@@ -0,0 +1,424 @@
+/* $Id: VBoxNetFltInternal.h 15923 2009-01-13 18:20:34Z vboxsync $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Internal Header.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+#ifndef ___VBoxNetFltInternal_h___
+#define ___VBoxNetFltInternal_h___
+
+#include <VBox/sup.h>
+#include <VBox/intnet.h>
+#include <iprt/semaphore.h>
+#include <iprt/assert.h>
+
+
+__BEGIN_DECLS
+
+/** Pointer to the globals. */
+typedef struct VBOXNETFLTGLOBALS *PVBOXNETFLTGLOBALS;
+
+
+/**
+ * The state of a filter driver instance.
+ *
+ * The state machine differs a bit between the platforms because of
+ * the way we hook into the stack. On some hosts we can dynamically
+ * attach when required (on CreateInstance) and on others we will
+ * have to connect when the network stack is bound up. These modes
+ * are called static and dynamic config and governed at compile time
+ * by the VBOXNETFLT_STATIC_CONFIG define.
+ *
+ * See sec_netflt_msc for more details on locking and synchronization.
+ */
+typedef enum VBOXNETFTLINSSTATE
+{
+ /** The usual invalid state. */
+ kVBoxNetFltInsState_Invalid = 0,
+ /** Initialization.
+ * We've reserved the interface name but need to attach to the actual
+ * network interface outside the lock to avoid deadlocks.
+ * In the dynamic case this happens during a Create(Instance) call.
+ * In the static case it happens during driver initialization. */
+ kVBoxNetFltInsState_Initializing,
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ /** Unconnected, not hooked up to a switch (static only).
+ * The filter driver instance has been instantiated and hooked up,
+ * waiting to be connected to an internal network. */
+ kVBoxNetFltInsState_Unconnected,
+#endif
+ /** Connected to an internal network. */
+ kVBoxNetFltInsState_Connected,
+ /** Disconnecting from the internal network and possibly the host network interface.
+ * Partly for reasons of deadlock avoidance again. */
+ kVBoxNetFltInsState_Disconnecting,
+ /** Destroying the instance
+ * Partly for reasons of deadlock avoidance again. */
+ kVBoxNetFltInsState_Destroying,
+ /** The instance has been disconnected from both the host and the internal network. */
+ kVBoxNetFltInsState_Destroyed,
+
+ /** The habitual 32-bit enum hack. */
+ kVBoxNetFltInsState_32BitHack = 0x7fffffff
+} VBOXNETFTLINSSTATE;
+
+
+/**
+ * The per-instance data of the VBox filter driver.
+ *
+ * This is data associated with a network interface / NIC / wossname which
+ * the filter driver has been or may be attached to. When possible it is
+ * attached dynamically, but this may not be possible on all OSes so we have
+ * to be flexible about things.
+ *
+ * A network interface / NIC / wossname can only have one filter driver
+ * instance attached to it. So, attempts at connecting an internal network
+ * to an interface that's already in use (connected to another internal network)
+ * will result in a VERR_SHARING_VIOLATION.
+ *
+ * Only one internal network can connect to a filter driver instance.
+ */
+typedef struct VBOXNETFLTINS
+{
+ /** Pointer to the next interface in the list. (VBOXNETFLTGLOBAL::pInstanceHead) */
+ struct VBOXNETFLTINS *pNext;
+ /** Our RJ-45 port.
+ * This is what the internal network plugs into. */
+ INTNETTRUNKIFPORT MyPort;
+ /** The RJ-45 port on the INTNET "switch".
+ * This is what we're connected to. */
+ PINTNETTRUNKSWPORT pSwitchPort;
+ /** Pointer to the globals. */
+ PVBOXNETFLTGLOBALS pGlobals;
+
+ /** The spinlock protecting the state variables and host interface handle. */
+ RTSPINLOCK hSpinlock;
+ /** The current interface state. */
+ VBOXNETFTLINSSTATE volatile enmState;
+ /** Active / Suspended indicator. */
+ bool volatile fActive;
+ /** Disconnected from the host network interface. */
+ bool volatile fDisconnectedFromHost;
+ /** Rediscovery is pending.
+ * cBusy will never reach zero during rediscovery, so which
+ * takes care of serializing rediscovery and disconnecting. */
+ bool volatile fRediscoveryPending;
+#if (ARCH_BITS == 32) && defined(__GNUC__)
+ uint32_t u32Padding; /**< Alignment padding, will assert in ASMAtomicUoWriteU64 otherwise. */
+#endif
+ /** The timestamp of the last rediscovery. */
+ uint64_t volatile NanoTSLastRediscovery;
+ /** Reference count. */
+ uint32_t volatile cRefs;
+ /** The busy count.
+ * This counts the number of current callers and pending packet. */
+ uint32_t volatile cBusy;
+ /** The event that is signaled when we go idle and that pfnWaitForIdle blocks on. */
+ RTSEMEVENT hEventIdle;
+
+ union
+ {
+#ifdef VBOXNETFLT_OS_SPECFIC
+ struct
+ {
+# if defined(RT_OS_DARWIN)
+ /** @name Darwin instance data.
+ * @{ */
+ /** Pointer to the darwin network interface we're attached to.
+ * This is treated as highly volatile and should only be read and retained
+ * while owning hSpinlock. Releasing references to this should not be done
+ * while owning it though as we might end up destroying it in some paths. */
+ ifnet_t volatile pIfNet;
+ /** The interface filter handle.
+ * Same access rules as with pIfNet. */
+ interface_filter_t volatile pIfFilter;
+ /** Whether we've need to set promiscuous mode when the interface comes up. */
+ bool volatile fNeedSetPromiscuous;
+ /** Whether we've successfully put the interface into to promiscuous mode.
+ * This is for dealing with the ENETDOWN case. */
+ bool volatile fSetPromiscuous;
+ /** The MAC address of the interface. */
+ RTMAC Mac;
+ /** @} */
+# elif defined(RT_OS_LINUX)
+ /** @name Linux instance data
+ * @{ */
+ /** Pointer to the device. */
+ struct net_device volatile *pDev;
+ /** Whether we've successfully put the interface into to promiscuous mode.
+ * This is for dealing with the ENETDOWN case. */
+ bool volatile fPromiscuousSet;
+ /** Whether device exists and physically attached. */
+ bool volatile fRegistered;
+ /** The MAC address of the interface. */
+ RTMAC Mac;
+ struct notifier_block Notifier;
+ struct packet_type PacketType;
+ struct sk_buff_head XmitQueue;
+ struct work_struct XmitTask;
+ /** @} */
+# elif defined(RT_OS_SOLARIS)
+ /** @name Solaris instance data.
+ * @{ */
+ /** Pointer to the bound IPv4 stream. */
+ void volatile *pvIp4Stream;
+ /** Pointer to the bound IPv6 stream. */
+ void volatile *pvIp6Stream;
+ /** Pointer to the bound ARP stream. */
+ void volatile *pvArpStream;
+ /** Pointer to the unbound promiscuous stream. */
+ void volatile *pvPromiscStream;
+ /** Layered device handle to the interface. */
+ ldi_handle_t hIface;
+ /** The MAC address of the interface. */
+ RTMAC Mac;
+ /** Mutex protection used for loopback. */
+ RTSEMFASTMUTEX hFastMtx;
+ /** @} */
+# elif defined(RT_OS_WINDOWS)
+ /** @name Windows instance data.
+ * @{ */
+ /** Filter driver device context. */
+ ADAPT IfAdaptor;
+ /** Packet worker thread info */
+ PACKET_QUEUE_WORKER PacketQueueWorker;
+ /** The MAC address of the interface. Caching MAC for performance reasons. */
+ RTMAC Mac;
+ /** mutex used to synchronize ADAPT init/deinit */
+ RTSEMMUTEX hAdaptMutex;
+ /** @} */
+# else
+# error "PORTME"
+# endif
+ } s;
+#endif
+ /** Padding. */
+#if defined(RT_OS_WINDOWS)
+# if defined(VBOX_NETFLT_ONDEMAND_BIND)
+ uint8_t abPadding[192];
+# else
+ uint8_t abPadding[1024];
+# endif
+#elif defined(RT_OS_LINUX)
+ uint8_t abPadding[320];
+#else
+ uint8_t abPadding[64];
+#endif
+ } u;
+
+ /** The interface name. */
+ char szName[1];
+} VBOXNETFLTINS;
+/** Pointer to the instance data of a host network filter driver. */
+typedef struct VBOXNETFLTINS *PVBOXNETFLTINS;
+
+AssertCompileMemberAlignment(VBOXNETFLTINS, NanoTSLastRediscovery, 8);
+#ifdef VBOXNETFLT_OS_SPECFIC
+AssertCompile(RT_SIZEOFMEMB(VBOXNETFLTINS, u.s) <= RT_SIZEOFMEMB(VBOXNETFLTINS, u.abPadding));
+#endif
+
+
+/**
+ * The global data of the VBox filter driver.
+ *
+ * This contains the bit required for communicating with support driver, VBoxDrv
+ * (start out as SupDrv).
+ */
+typedef struct VBOXNETFLTGLOBALS
+{
+ /** Mutex protecting the list of instances and state changes. */
+ RTSEMFASTMUTEX hFastMtx;
+ /** Pointer to a list of instance data. */
+ PVBOXNETFLTINS pInstanceHead;
+
+ /** The INTNET trunk network interface factory. */
+ INTNETTRUNKFACTORY TrunkFactory;
+ /** The SUPDRV component factory registration. */
+ SUPDRVFACTORY SupDrvFactory;
+ /** The number of current factory references. */
+ int32_t volatile cFactoryRefs;
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ /* wait timer event */
+ RTSEMEVENT hTimerEvent;
+#endif
+ /** The SUPDRV IDC handle (opaque struct). */
+ SUPDRVIDCHANDLE SupDrvIDC;
+} VBOXNETFLTGLOBALS;
+
+
+DECLHIDDEN(int) vboxNetFltInitGlobals(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(int) vboxNetFltTryDeleteGlobals(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(bool) vboxNetFltCanUnload(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(PVBOXNETFLTINS) vboxNetFltFindInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName);
+
+DECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy);
+DECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy);
+
+#ifdef VBOXNETFLT_STATIC_CONFIG
+DECLHIDDEN(int) vboxNetFltSearchCreateInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PVBOXNETFLTINS *ppInstance, void * pContext);
+DECLHIDDEN(int) vboxNetFltInitGlobalsBase(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(int) vboxNetFltInitIdc(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(void) vboxNetFltDeleteGlobalsBase(PVBOXNETFLTGLOBALS pGlobals);
+DECLHIDDEN(int) vboxNetFltTryDeleteIdc(PVBOXNETFLTGLOBALS pGlobals);
+#endif
+
+
+/** @name The OS specific interface.
+ * @{ */
+/**
+ * Try rediscover the host interface.
+ *
+ * This is called periodically from the transmit path if we're marked as
+ * disconnected from the host. There is no chance of a race here.
+ *
+ * @returns true if the interface was successfully rediscovered and reattach,
+ * otherwise false.
+ * @param pThis The new instance.
+ */
+DECLHIDDEN(bool) vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis);
+
+/**
+ * Transmits a frame.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ * @param pSG The (scatter/)gather list.
+ * @param fDst The destination mask. At least one bit will be set.
+ *
+ * @remarks Owns the out-bound trunk port semaphore.
+ */
+DECLHIDDEN(int) vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
+
+/**
+ * Checks if the interface is in promiscuous mode from the host perspective.
+ *
+ * If it is, then the internal networking switch will send frames
+ * heading for the wire to the host as well.
+ *
+ * @see INTNETTRUNKIFPORT::pfnIsPromiscuous for more details.
+ *
+ * @returns true / false accordingly.
+ * @param pThis The instance.
+ *
+ * @remarks Owns the network lock and the out-bound trunk port semaphores.
+ */
+DECLHIDDEN(bool) vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis);
+
+/**
+ * Get the MAC address of the interface we're attached to.
+ *
+ * Used by the internal networking switch for implementing the
+ * shared-MAC-on-the-wire mode.
+ *
+ * @param pThis The instance.
+ * @param pMac Where to store the MAC address.
+ * If you don't know, set all the bits except the first (the multicast one).
+ *
+ * @remarks Owns the network lock and the out-bound trunk port semaphores.
+ */
+DECLHIDDEN(void) vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac);
+
+/**
+ * Checks if the specified MAC address is for any of the host interfaces.
+ *
+ * Used by the internal networking switch to decide the destination(s)
+ * of a frame.
+ *
+ * @returns true / false accordingly.
+ * @param pThis The instance.
+ * @param pMac The MAC address.
+ *
+ * @remarks Owns the network lock and the out-bound trunk port semaphores.
+ */
+DECLHIDDEN(bool) vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac);
+
+/**
+ * This is called when activating or suspending the instance.
+ *
+ * Use this method to enable and disable promiscuous mode on
+ * the interface to prevent unnecessary interrupt load.
+ *
+ * It is only called when the state changes.
+ *
+ * @param pThis The instance.
+ *
+ * @remarks Owns the lock for the out-bound trunk port.
+ */
+DECLHIDDEN(void) vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive);
+
+/**
+ * This is called to when disconnecting from a network.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks May own the semaphores for the global list, the network lock and the out-bound trunk port.
+ */
+DECLHIDDEN(int) vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis);
+
+/**
+ * This is called to when connecting to a network.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks Owns the semaphores for the global list, the network lock and the out-bound trunk port.
+ */
+DECLHIDDEN(int) vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis);
+
+/**
+ * Counter part to vboxNetFltOsInitInstance().
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks May own the semaphores for the global list, the network lock and the out-bound trunk port.
+ */
+DECLHIDDEN(void) vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis);
+
+/**
+ * This is called to attach to the actual host interface
+ * after linking the instance into the list.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks Owns no locks.
+ */
+DECLHIDDEN(int) vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ , void * pContext
+#endif
+ );
+
+/**
+ * This is called to perform structure initializations.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks Owns no locks.
+ */
+DECLHIDDEN(int) vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis);
+/** @} */
+
+
+__END_DECLS
+
+#endif
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/darwin/Info.plist b/src/VBox/HostDrivers/VBoxNetFlt/darwin/Info.plist
new file mode 100644
index 000000000..940a884e2
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/darwin/Info.plist
@@ -0,0 +1,32 @@
+
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleExecutable</key> <string>VBoxNetFlt</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxNetFlt</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>VBoxNetFlt</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>CFBundleGetInfoString</key> <string>VirtualBox @VBOX_VERSION_STRING@, © 2007 Sun Microsystems, Inc.</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ </dict>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.bsd</key> <string>8.8.1</string>
+ <key>com.apple.kpi.mach</key> <string>8.8.1</string>
+ <key>com.apple.kpi.libkern</key> <string>8.8.1</string>
+ <key>com.apple.kpi.unsupported</key> <string>8.8.1</string>
+ <key>com.apple.kpi.iokit</key> <string>8.8.1</string>
+ <key>org.virtualbox.kext.VBoxDrv</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+<!--
+ <key>com.apple.kernel.bsd</key> <string>7.9.9</string>
+ <key>com.apple.kernel.mach</key> <string>7.9.9</string>
+-->
+ </dict>
+</dict>
+</plist>
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/darwin/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/darwin/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/darwin/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp b/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp
new file mode 100644
index 000000000..6d2afe61f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp
@@ -0,0 +1,1183 @@
+/* $Id: VBoxNetFlt-darwin.cpp 15527 2008-12-15 18:11:08Z vboxsync $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Darwin Specific Code.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+/*
+ * Deal with conflicts first.
+ * PVM - BSD mess, that FreeBSD has correct a long time ago.
+ * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
+ */
+#include <iprt/types.h>
+#include <sys/param.h>
+#undef PVM
+
+#include <IOKit/IOLib.h> /* Assert as function */
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/time.h>
+#include <iprt/net.h>
+
+#include <mach/kmod.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/kern_event.h>
+#include <net/kpi_interface.h>
+__BEGIN_DECLS /* Buggy 10.4 headers, fixed in 10.5. */
+#include <sys/kpi_mbuf.h>
+#include <net/kpi_interfacefilter.h>
+__END_DECLS
+#include <net/if.h>
+
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "../VBoxNetFltInternal.h"
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The maximum number of SG segments.
+ * Used to prevent stack overflow and similar bad stuff. */
+#define VBOXNETFLT_DARWIN_MAX_SEGS 32
+
+#if 0
+/** For testing extremely segmented frames. */
+#define VBOXNETFLT_DARWIN_TEST_SEG_SIZE 14
+#endif
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+__BEGIN_DECLS
+static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData);
+static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData);
+__END_DECLS
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * The mbuf tag data.
+ *
+ * We have to associate the ethernet header with each packet we're sending
+ * because things like icmp will inherit the tag it self so the tag along
+ * isn't sufficent to identify our mbufs. For the icmp scenario the ethernet
+ * header naturarlly changes before the packet is send pack, so let check it.
+ */
+typedef struct VBOXNETFLTTAG
+{
+ /** The ethernet header of the outgoing frame. */
+ RTNETETHERHDR EthHdr;
+} VBOXNETFLTTAG;
+/** Pointer to a VBoxNetFlt mbuf tag. */
+typedef VBOXNETFLTTAG *PVBOXNETFLTTAG;
+/** Pointer to a const VBoxNetFlt mbuf tag. */
+typedef VBOXNETFLTTAG const *PCVBOXNETFLTTAG;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Declare the module stuff.
+ */
+__BEGIN_DECLS
+extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
+extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
+
+KMOD_EXPLICIT_DECL(VBoxNetFlt, VBOX_VERSION_STRING, _start, _stop)
+DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxNetFltDarwinStart;
+DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxNetFltDarwinStop;
+DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
+__END_DECLS
+
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+
+/** The unique tag id for this module.
+ * This is basically a unique string hash that lives on untill reboot.
+ * It is used for tagging mbufs. */
+static mbuf_tag_id_t g_idTag;
+
+/** the offset of the struct ifnet::if_pcount variable. */
+static unsigned g_offIfNetPCount = sizeof(void *) * (1 /*if_softc*/ + 1 /*if_name*/ + 2 /*if_link*/ + 2 /*if_addrhead*/ + 1 /*if_check_multi*/)
+ + sizeof(u_long) /*if_refcnt*/;
+/** Macro for accessing ifnet::if_pcount. */
+#define VBOX_GET_PCOUNT(pIfNet) ( *(int *)((uintptr_t)pIfNet + g_offIfNetPCount) )
+
+
+/**
+ * Start the kernel module.
+ */
+static kern_return_t VBoxNetFltDarwinStart(struct kmod_info *pKModInfo, void *pvData)
+{
+ int rc;
+
+ /*
+ * Initialize IPRT and find our module tag id.
+ * (IPRT is shared with VBoxDrv, it creates the loggers.)
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBoxNetFltDarwinStart\n"));
+ errno_t err = mbuf_tag_id_find("org.VirtualBox.kext.VBoxFltDrv", &g_idTag);
+ if (!err)
+ {
+ /*
+ * Initialize the globals and connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel(("VBoxFltDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
+ return KMOD_RETURN_SUCCESS;
+ }
+
+ LogRel(("VBoxFltDrv: failed to initialize device extension (rc=%d)\n", rc));
+ }
+ else
+ LogRel(("VBoxFltDrv: mbuf_tag_id_find failed, err=%d\n", err));
+ RTR0Term();
+ }
+ else
+ printf("VBoxFltDrv: failed to initialize IPRT (rc=%d)\n", rc);
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ return KMOD_RETURN_FAILURE;
+}
+
+
+/**
+ * Stop the kernel module.
+ */
+static kern_return_t VBoxNetFltDarwinStop(struct kmod_info *pKModInfo, void *pvData)
+{
+ Log(("VBoxNetFltDarwinStop\n"));
+
+ /*
+ * Refuse to unload if anyone is currently using the filter driver.
+ * This is important as I/O kit / xnu will to be able to do usage
+ * tracking for us!
+ */
+ int rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltGlobals);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBoxNetFltDarwinStop - failed, busy.\n"));
+ return KMOD_RETURN_FAILURE;
+ }
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+
+ RTR0Term();
+
+ return KMOD_RETURN_SUCCESS;
+}
+
+
+/**
+ * Reads and retains the host interface handle.
+ *
+ * @returns The handle, NULL if detached.
+ * @param pThis
+ */
+DECLINLINE(ifnet_t) vboxNetFltDarwinRetainIfNet(PVBOXNETFLTINS pThis)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ ifnet_t pIfNet = NULL;
+
+ /*
+ * Be careful here to avoid problems racing the detached callback.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ if (!ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
+ {
+ pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
+ if (pIfNet)
+ ifnet_reference(pIfNet);
+ }
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ return pIfNet;
+}
+
+
+/**
+ * Release the host interface handle previously retained
+ * by vboxNetFltDarwinRetainIfNet.
+ *
+ * @param pThis The instance.
+ * @param pIfNet The vboxNetFltDarwinRetainIfNet return value, NULL is fine.
+ */
+DECLINLINE(void) vboxNetFltDarwinReleaseIfNet(PVBOXNETFLTINS pThis, ifnet_t pIfNet)
+{
+ NOREF(pThis);
+ if (pIfNet)
+ ifnet_release(pIfNet);
+}
+
+
+/**
+ * Checks whether this is an mbuf created by vboxNetFltDarwinMBufFromSG,
+ * i.e. a buffer which we're pushing and should be ignored by the filter callbacks.
+ *
+ * @returns true / false accordingly.
+ * @param pThis The instance.
+ * @param pMBuf The mbuf.
+ * @param pvFrame The frame pointer, optional.
+ */
+DECLINLINE(bool) vboxNetFltDarwinMBufIsOur(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
+{
+ NOREF(pThis);
+
+ /*
+ * Lookup the tag set by vboxNetFltDarwinMBufFromSG.
+ */
+ PCVBOXNETFLTTAG pTagData;
+ size_t cbTagData;
+ errno_t err = mbuf_tag_find(pMBuf, g_idTag, 0 /* type */, &cbTagData, (void **)&pTagData);
+ if (err)
+ return false;
+ AssertReturn(cbTagData == sizeof(*pTagData), false);
+
+ /*
+ * Dig out the ethernet header from the mbuf.
+ */
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvFrame;
+ if (!pEthHdr)
+ pEthHdr = (PCRTNETETHERHDR)mbuf_pkthdr_header(pMBuf);
+ if (!pEthHdr)
+ pEthHdr = (PCRTNETETHERHDR)mbuf_data(pMBuf);
+ /* ASSUMING that there is enough data to work on! */
+ if ( pEthHdr->DstMac.au8[0] != pTagData->EthHdr.DstMac.au8[0]
+ || pEthHdr->DstMac.au8[1] != pTagData->EthHdr.DstMac.au8[1]
+ || pEthHdr->DstMac.au8[2] != pTagData->EthHdr.DstMac.au8[2]
+ || pEthHdr->DstMac.au8[3] != pTagData->EthHdr.DstMac.au8[3]
+ || pEthHdr->DstMac.au8[4] != pTagData->EthHdr.DstMac.au8[4]
+ || pEthHdr->DstMac.au8[5] != pTagData->EthHdr.DstMac.au8[5]
+ || pEthHdr->SrcMac.au8[0] != pTagData->EthHdr.SrcMac.au8[0]
+ || pEthHdr->SrcMac.au8[1] != pTagData->EthHdr.SrcMac.au8[1]
+ || pEthHdr->SrcMac.au8[2] != pTagData->EthHdr.SrcMac.au8[2]
+ || pEthHdr->SrcMac.au8[3] != pTagData->EthHdr.SrcMac.au8[3]
+ || pEthHdr->SrcMac.au8[4] != pTagData->EthHdr.SrcMac.au8[4]
+ || pEthHdr->SrcMac.au8[5] != pTagData->EthHdr.SrcMac.au8[5]
+ || pEthHdr->EtherType != pTagData->EthHdr.EtherType)
+ {
+ Log3(("tagged, but the ethernet header has changed\n"));
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Internal worker that create a darwin mbuf for a (scatter/)gather list.
+ *
+ * @returns Pointer to the mbuf.
+ * @param pThis The instance.
+ * @param pSG The (scatter/)gather list.
+ */
+static mbuf_t vboxNetFltDarwinMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG)
+{
+ /// @todo future? mbuf_how_t How = preemtion enabled ? MBUF_DONTWAIT : MBUF_WAITOK;
+ mbuf_how_t How = MBUF_WAITOK;
+
+ /*
+ * We can't make use of the physical addresses on darwin because the way the
+ * mbuf / cluster stuffe works (see mbuf_data_to_physical and mcl_to_paddr).
+ * So, because we're lazy, we will ASSUME that all SGs coming from INTNET
+ * will only contain one single segment.
+ */
+ Assert(pSG->cSegsUsed == 1);
+ Assert(pSG->cbTotal == pSG->aSegs[0].cb);
+ Assert(pSG->cbTotal > 0);
+
+ /*
+ * We need some way of getting back to our instance data when
+ * the mbuf is freed, so use pvUserData for this.
+ * -- this is not relevant anylonger! --
+ */
+ Assert(!pSG->pvUserData || pSG->pvUserData == pThis);
+ Assert(!pSG->pvUserData2);
+ pSG->pvUserData = pThis;
+
+ /*
+ * Allocate a packet and copy over the data.
+ *
+ * Using mbuf_attachcluster() here would've been nice but there are two
+ * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates
+ * that it's not supposed to be used for really external buffers. The 2nd
+ * point might be argued against considering that the only m_clattach user
+ * is mallocs memory for the ext mbuf and not doing what's stated in the docs.
+ * However, it's hard to tell if these m_clattach buffers actually makes it
+ * to the NICs or not, and even if they did, the NIC would need the physical
+ * addresses for the pages they contain and might end up copying the data
+ * to a new mbuf anyway.
+ *
+ * So, in the end it's better to just do it the simple way that will work
+ * 100%, even if it involes some extra work (alloc + copy) we really wished
+ * to avoid.
+ */
+ mbuf_t pPkt = NULL;
+ errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt);
+ if (!err)
+ {
+ /* Skip zero sized memory buffers (paranoia). */
+ mbuf_t pCur = pPkt;
+ while (pCur && !mbuf_maxlen(pCur))
+ pCur = mbuf_next(pCur);
+ Assert(pCur);
+
+ /* Set the required packet header attributes. */
+ mbuf_pkthdr_setlen(pPkt, pSG->cbTotal);
+ mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur));
+
+ /* Special case the single buffer copy. */
+ if ( mbuf_next(pCur)
+ && mbuf_maxlen(pCur) >= pSG->cbTotal)
+ {
+ mbuf_setlen(pCur, pSG->cbTotal);
+ memcpy(mbuf_data(pCur), pSG->aSegs[0].pv, pSG->cbTotal);
+ }
+ else
+ {
+ /* Multi buffer copying. */
+ size_t cbSrc = pSG->cbTotal;
+ uint8_t const *pbSrc = (uint8_t const *)pSG->aSegs[0].pv;
+ while (cbSrc > 0 && pCur)
+ {
+ size_t cb = mbuf_maxlen(pCur);
+ if (cbSrc < cb)
+ cb = cbSrc;
+ mbuf_setlen(pCur, cb);
+ memcpy(mbuf_data(pCur), pbSrc, cb);
+
+ /* advance */
+ pbSrc += cb;
+ cbSrc -= cb;
+ pCur = mbuf_next(pCur);
+ }
+ }
+ if (!err)
+ {
+ /*
+ * Tag the packet and return successfully.
+ */
+ PVBOXNETFLTTAG pTagData;
+ err = mbuf_tag_allocate(pPkt, g_idTag, 0 /* type */, sizeof(VBOXNETFLTTAG) /* tag len */, How, (void **)&pTagData);
+ if (!err)
+ {
+ Assert(pSG->aSegs[0].cb >= sizeof(pTagData->EthHdr));
+ memcpy(&pTagData->EthHdr, pSG->aSegs[0].pv, sizeof(pTagData->EthHdr));
+ return pPkt;
+ }
+
+ /* bailout: */
+ AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
+ }
+
+ mbuf_freem(pPkt);
+ }
+ else
+ AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err));
+ pSG->pvUserData = NULL;
+
+ return NULL;
+}
+
+
+/**
+ * Calculates the number of segments required to represent the mbuf.
+ *
+ * @returns Number of segments.
+ * @param pThis The instance.
+ * @param pMBuf The mbuf.
+ * @param pvFrame The frame pointer, optional.
+ */
+DECLINLINE(unsigned) vboxNetFltDarwinMBufCalcSGSegs(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame)
+{
+ NOREF(pThis);
+
+ /*
+ * Count the buffers in the chain.
+ */
+ unsigned cSegs = 0;
+ for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
+ if (mbuf_len(pCur))
+ cSegs++;
+ else if ( !cSegs
+ && pvFrame
+ && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
+ cSegs++;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ /*
+ * Add one buffer if the total is less than the ethernet minimum 60 bytes.
+ * This may allocate a segment too much if the ethernet header is separated,
+ * but that shouldn't harm us much.
+ */
+ if (mbuf_pkthdr_len(pMBuf) < 60)
+ cSegs++;
+#endif
+
+#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
+ /* maximize the number of segments. */
+ cSegs = RT_MAX(VBOXNETFLT_DARWIN_MAX_SEGS - 1, cSegs);
+#endif
+
+ return cSegs ? cSegs : 1;
+}
+
+
+/**
+ * Initializes a SG list from an mbuf.
+ *
+ * @returns Number of segments.
+ * @param pThis The instance.
+ * @param pMBuf The mbuf.
+ * @param pSG The SG.
+ * @param pvFrame The frame pointer, optional.
+ * @param cSegs The number of segments allocated for the SG.
+ * This should match the number in the mbuf exactly!
+ * @param fSrc The source of the frame.
+ */
+DECLINLINE(void) vboxNetFltDarwinMBufToSG(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
+{
+ NOREF(pThis);
+
+ pSG->pvOwnerData = NULL;
+ pSG->pvUserData = NULL;
+ pSG->pvUserData2 = NULL;
+ pSG->cUsers = 1;
+ pSG->fFlags = INTNETSG_FLAGS_TEMP;
+ pSG->cSegsAlloc = cSegs;
+
+ /*
+ * Walk the chain and convert the buffers to segments.
+ */
+ unsigned iSeg = 0;
+ pSG->cbTotal = 0;
+ for (mbuf_t pCur = pMBuf; pCur; pCur = mbuf_next(pCur))
+ {
+ size_t cbSeg = mbuf_len(pCur);
+ if (cbSeg)
+ {
+ void *pvSeg = mbuf_data(pCur);
+
+ /* deal with pvFrame */
+ if (!iSeg && pvFrame && pvFrame != pvSeg)
+ {
+ void *pvStart = mbuf_datastart(pMBuf);
+ uintptr_t offSeg = (uintptr_t)pvSeg - (uintptr_t)pvStart;
+ uintptr_t offSegEnd = offSeg + cbSeg;
+ Assert(pvStart && pvSeg && offSeg < mbuf_maxlen(pMBuf) && offSegEnd <= mbuf_maxlen(pMBuf)); NOREF(offSegEnd);
+ uintptr_t offFrame = (uintptr_t)pvFrame - (uintptr_t)pvStart;
+ if (RT_LIKELY(offFrame < offSeg))
+ {
+ pvSeg = pvFrame;
+ cbSeg += offSeg - offFrame;
+ }
+ else
+ AssertMsgFailed(("pvFrame=%p pvStart=%p pvSeg=%p offSeg=%p cbSeg=%#zx offSegEnd=%p offFrame=%p maxlen=%#zx\n",
+ pvFrame, pvStart, pvSeg, offSeg, cbSeg, offSegEnd, offFrame, mbuf_maxlen(pMBuf)));
+ pvFrame = NULL;
+ }
+
+ AssertBreak(iSeg < cSegs);
+ pSG->cbTotal += cbSeg;
+ pSG->aSegs[iSeg].cb = cbSeg;
+ pSG->aSegs[iSeg].pv = pvSeg;
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ iSeg++;
+ }
+ /* The pvFrame might be in a now empty buffer. */
+ else if ( !iSeg
+ && pvFrame
+ && (uintptr_t)pvFrame - (uintptr_t)mbuf_datastart(pMBuf) < mbuf_maxlen(pMBuf))
+ {
+ cbSeg = (uintptr_t)mbuf_datastart(pMBuf) + mbuf_maxlen(pMBuf) - (uintptr_t)pvFrame;
+ pSG->cbTotal += cbSeg;
+ pSG->aSegs[iSeg].cb = cbSeg;
+ pSG->aSegs[iSeg].pv = pvFrame;
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ iSeg++;
+ pvFrame = NULL;
+ }
+ }
+
+ Assert(iSeg && iSeg <= cSegs);
+ pSG->cSegsUsed = iSeg;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ /*
+ * Add a trailer if the frame is too small.
+ *
+ * Since we're getting to the packet before it is framed, it has not
+ * yet been padded. The current solution is to add a segment pointing
+ * to a buffer containing all zeros and pray that works for all frames...
+ */
+ if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
+ {
+ AssertReturnVoid(iSeg < cSegs);
+
+ static uint8_t const s_abZero[128] = {0};
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
+ pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
+ pSG->cbTotal = 60;
+ pSG->cSegsUsed++;
+ }
+#endif
+
+#ifdef VBOXNETFLT_DARWIN_TEST_SEG_SIZE
+ /*
+ * Redistribute the segments.
+ */
+ if (pSG->cSegsUsed < pSG->cSegsAlloc)
+ {
+ /* copy the segments to the end. */
+ int iSrc = pSG->cSegsUsed;
+ int iDst = pSG->cSegsAlloc;
+ while (iSrc > 0)
+ {
+ iDst--;
+ iSrc--;
+ pSG->aSegs[iDst] = pSG->aSegs[iSrc];
+ }
+
+ /* create small segments from the start. */
+ pSG->cSegsUsed = pSG->cSegsAlloc;
+ iSrc = iDst;
+ iDst = 0;
+ while ( iDst < iSrc
+ && iDst < pSG->cSegsAlloc)
+ {
+ pSG->aSegs[iDst].Phys = NIL_RTHCPHYS;
+ pSG->aSegs[iDst].pv = pSG->aSegs[iSrc].pv;
+ pSG->aSegs[iDst].cb = RT_MIN(pSG->aSegs[iSrc].cb, VBOXNETFLT_DARWIN_TEST_SEG_SIZE);
+ if (pSG->aSegs[iDst].cb != pSG->aSegs[iSrc].cb)
+ {
+ pSG->aSegs[iSrc].cb -= pSG->aSegs[iDst].cb;
+ pSG->aSegs[iSrc].pv = (uint8_t *)pSG->aSegs[iSrc].pv + pSG->aSegs[iDst].cb;
+ }
+ else if (++iSrc >= pSG->cSegsAlloc)
+ {
+ pSG->cSegsUsed = iDst + 1;
+ break;
+ }
+ iDst++;
+ }
+ }
+#endif
+
+ AssertMsg(!pvFrame, ("pvFrame=%p pMBuf=%p iSeg=%d\n", pvFrame, pMBuf, iSeg));
+}
+
+
+/**
+ *
+ * @see iff_detached_func in the darwin kpi.
+ */
+static void vboxNetFltDarwinIffDetached(void *pvThis, ifnet_t pIfNet)
+{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+ LogFlow(("vboxNetFltDarwinIffDetached: pThis=%p NanoTS=%RU64 (%d)\n",
+ pThis, NanoTS, VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
+
+ Assert(!pThis->fDisconnectedFromHost);
+ Assert(!pThis->fRediscoveryPending);
+
+ /*
+ * If we've put it into promiscuous mode, undo that now. If we don't
+ * the if_pcount will go all wrong when it's replugged.
+ */
+ if (ASMAtomicXchgBool(&pThis->u.s.fSetPromiscuous, false))
+ ifnet_set_promiscuous(pIfNet, 0);
+
+ /*
+ * We carefully take the spinlock and increase the interface reference
+ * behind it in order to avoid problematic races with the detached callback.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+
+ pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
+ int cPromisc = VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : - 1;
+
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfNet, NULL);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, NULL);
+ ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
+ pThis->u.s.fSetPromiscuous = false;
+ ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, NanoTS);
+ ASMAtomicUoWriteBool(&pThis->fRediscoveryPending, false);
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
+
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ if (pIfNet)
+ ifnet_release(pIfNet);
+ LogRel(("VBoxNetFlt: was detached from '%s' (%d)\n", pThis->szName, cPromisc));
+}
+
+
+/**
+ *
+ * @see iff_ioctl_func in the darwin kpi.
+ */
+static errno_t vboxNetFltDarwinIffIoCtl(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, u_long uCmd, void *pvArg)
+{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
+ LogFlow(("vboxNetFltDarwinIffIoCtl: pThis=%p uCmd=%lx\n", pThis, uCmd));
+
+ /*
+ * Update fOtherPromiscuous.
+ */
+ /** @todo we'll have to find the offset of if_pcount to get this right! */
+ //if (uCmd == SIOCSIFFLAGS)
+ //{
+ //
+ //}
+
+ /*
+ * We didn't handle it, continue processing.
+ */
+ NOREF(pThis);
+ NOREF(eProtocol);
+ NOREF(uCmd);
+ NOREF(pvArg);
+ return EOPNOTSUPP;
+}
+
+
+/**
+ *
+ * @see iff_event_func in the darwin kpi.
+ */
+static void vboxNetFltDarwinIffEvent(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, const struct kev_msg *pEvMsg)
+{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis;
+ LogFlow(("vboxNetFltDarwinIffEvent: pThis=%p\n", pThis));
+
+ NOREF(pThis);
+ NOREF(pIfNet);
+ NOREF(eProtocol);
+ NOREF(pEvMsg);
+
+ /*
+ * Watch out for the interface going online / offline.
+ */
+ if ( VALID_PTR(pThis)
+ && VALID_PTR(pEvMsg)
+ && pEvMsg->vendor_code == KEV_VENDOR_APPLE
+ && pEvMsg->kev_class == KEV_NETWORK_CLASS
+ && pEvMsg->kev_subclass == KEV_DL_SUBCLASS)
+ {
+ if (pThis->u.s.pIfNet == pIfNet)
+ {
+ if (pEvMsg->event_code == KEV_DL_LINK_ON)
+ {
+ if (ASMAtomicUoReadBool(&pThis->u.s.fNeedSetPromiscuous))
+ {
+ /* failed to bring it online. */
+ errno_t err = ifnet_set_promiscuous(pIfNet, 1);
+ if (!err)
+ {
+ ASMAtomicWriteBool(&pThis->u.s.fSetPromiscuous, true);
+ ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
+ Log(("vboxNetFltDarwinIffEvent: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else
+ Log(("vboxNetFltDarwinIffEvent: ifnet_set_promiscuous failed on %s, err=%d (%d)\n", pThis->szName, err, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else if ( ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous)
+ && !(ifnet_flags(pIfNet) & IFF_PROMISC))
+ {
+ /* Try fix the inconsistency. */
+ errno_t err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
+ if (!err)
+ err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
+ if (!err && (ifnet_flags(pIfNet) & IFF_PROMISC))
+ Log(("vboxNetFltDarwinIffEvent: fixed IFF_PROMISC on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
+ else
+ Log(("vboxNetFltDarwinIffEvent: failed to fix IFF_PROMISC on %s, err=%d flags=%#x (%d)\n",
+ pThis->szName, err, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else
+ Log(("vboxNetFltDarwinIffEvent: online, '%s'. flags=%#x (%d)\n", pThis->szName, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else if (pEvMsg->event_code == KEV_DL_LINK_OFF)
+ Log(("vboxNetFltDarwinIffEvent: %s goes down (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else
+ Log(("vboxNetFltDarwinIffEvent: pThis->u.s.pIfNet=%p pIfNet=%p (%d)\n", pThis->u.s.pIfNet, pIfNet, VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1));
+ }
+ else if (VALID_PTR(pEvMsg))
+ Log(("vboxNetFltDarwinIffEvent: vendor_code=%#x kev_class=%#x kev_subclass=%#x event_code=%#x\n",
+ pEvMsg->vendor_code, pEvMsg->kev_class, pEvMsg->kev_subclass, pEvMsg->event_code));
+}
+
+
+/**
+ * Internal worker for vboxNetFltDarwinIffInput and vboxNetFltDarwinIffOutput,
+ *
+ * @returns 0 or EJUSTRETURN.
+ * @param pThis The instance.
+ * @param pMBuf The mbuf.
+ * @param pvFrame The start of the frame, optional.
+ * @param fSrc Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value.
+ * @param eProtocol The protocol.
+ */
+static errno_t vboxNetFltDarwinIffInputOutputWorker(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame,
+ uint32_t fSrc, protocol_family_t eProtocol)
+{
+ /*
+ * Drop it immediately?
+ */
+ Log2(("vboxNetFltDarwinIffInputOutputWorker: pThis=%p pMBuf=%p pvFrame=%p fSrc=%#x cbPkt=%x\n",
+ pThis, pMBuf, pvFrame, fSrc, pMBuf ? mbuf_pkthdr_len(pMBuf) : -1));
+ if (!pMBuf)
+ return 0;
+#if 0 /* debugging lost icmp packets */
+ if (mbuf_pkthdr_len(pMBuf) > 0x300)
+ {
+ uint8_t *pb = (uint8_t *)(pvFrame ? pvFrame : mbuf_data(pMBuf));
+ Log3(("D=%.6Rhxs S=%.6Rhxs T=%04x IFF\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
+ }
+#endif
+ if (vboxNetFltDarwinMBufIsOur(pThis, pMBuf, pvFrame))
+ return 0;
+
+ /*
+ * Active? Retain the instance and increment the busy counter.
+ */
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ vboxNetFltRetain(pThis, true /* fBusy */);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ if (!fActive)
+ return 0;
+
+ /*
+ * Finalize out-bound packets since the stack puts off finalizing
+ * TCP/IP checksums as long as possible.
+ * ASSUMES this only applies to outbound IP packets.
+ */
+ if ( (fSrc & INTNETTRUNKDIR_HOST)
+ && eProtocol == PF_INET)
+ {
+ Assert(!pvFrame);
+ mbuf_outbound_finalize(pMBuf, eProtocol, sizeof(RTNETETHERHDR));
+ }
+
+ /*
+ * Create a (scatter/)gather list for the mbuf and feed it to the internal network.
+ */
+ bool fDropIt = false;
+ unsigned cSegs = vboxNetFltDarwinMBufCalcSGSegs(pThis, pMBuf, pvFrame);
+ if (cSegs < VBOXNETFLT_DARWIN_MAX_SEGS)
+ {
+ PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ vboxNetFltDarwinMBufToSG(pThis, pMBuf, pvFrame, pSG, cSegs, fSrc);
+
+ fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
+ if (fDropIt)
+ mbuf_freem(pMBuf);
+ }
+
+ vboxNetFltRelease(pThis, true /* fBusy */);
+
+ return fDropIt ? EJUSTRETURN : 0;
+}
+
+
+/**
+ * From the host.
+ *
+ * @see iff_output_func in the darwin kpi.
+ */
+static errno_t vboxNetFltDarwinIffOutput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf)
+{
+ /** @todo there was some note about the ethernet header here or something like that... */
+
+ NOREF(eProtocol);
+ NOREF(pIfNet);
+ return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, NULL, INTNETTRUNKDIR_HOST, eProtocol);
+}
+
+
+/**
+ * From the wire.
+ *
+ * @see iff_input_func in the darwin kpi.
+ */
+static errno_t vboxNetFltDarwinIffInput(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, mbuf_t *ppMBuf, char **ppchFrame)
+{
+ NOREF(eProtocol);
+ NOREF(pIfNet);
+ return vboxNetFltDarwinIffInputOutputWorker((PVBOXNETFLTINS)pvThis, *ppMBuf, *ppchFrame, INTNETTRUNKDIR_WIRE, eProtocol);
+}
+
+
+/**
+ * Internal worker for vboxNetFltOsInitInstance and vboxNetFltOsMaybeRediscovered.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param fRediscovery If set we're doing a rediscovery attempt, so, don't
+ * flood the release log.
+ */
+static int vboxNetFltDarwinAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery)
+{
+ LogFlow(("vboxNetFltDarwinAttachToInterface: pThis=%p (%s)\n", pThis, pThis->szName));
+
+ /*
+ * Locate the interface first.
+ *
+ * The pIfNet member is updated before iflt_attach is called and used
+ * to deal with the hypothetical case where someone rips out the
+ * interface immediately after our iflt_attach call.
+ */
+ ifnet_t pIfNet = NULL;
+ errno_t err = ifnet_find_by_name(pThis->szName, &pIfNet);
+ if (err)
+ {
+ Assert(err == ENXIO);
+ if (!fRediscovery)
+ LogRel(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
+ else
+ Log(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+ }
+
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfNet, pIfNet);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ /*
+ * Get the mac address while we still have a valid ifnet reference.
+ */
+ err = ifnet_lladdr_copy_bytes(pIfNet, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
+ if (!err)
+ {
+ /*
+ * Try attach the filter.
+ */
+ struct iff_filter RegRec;
+ RegRec.iff_cookie = pThis;
+ RegRec.iff_name = "VBoxNetFlt";
+ RegRec.iff_protocol = 0;
+ RegRec.iff_input = vboxNetFltDarwinIffInput;
+ RegRec.iff_output = vboxNetFltDarwinIffOutput;
+ RegRec.iff_event = vboxNetFltDarwinIffEvent;
+ RegRec.iff_ioctl = vboxNetFltDarwinIffIoCtl;
+ RegRec.iff_detached = vboxNetFltDarwinIffDetached;
+ interface_filter_t pIfFilter = NULL;
+ err = iflt_attach(pIfNet, &RegRec, &pIfFilter);
+ Assert(err || pIfFilter);
+
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ pIfNet = (ifnet_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfNet);
+ if (pIfNet && !err)
+ {
+ ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, pIfFilter);
+ pIfNet = NULL; /* don't dereference it */
+ }
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ }
+
+ /* Release the interface on failure. */
+ if (pIfNet)
+ ifnet_release(pIfNet);
+
+ int rc = RTErrConvertFromErrno(err);
+ if (RT_SUCCESS(rc))
+ LogRel(("VBoxFltDrv: attached to '%s' / %.*Rhxs\n", pThis->szName, sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
+ else
+ LogRel(("VBoxFltDrv: failed to attach to ifnet '%s' (err=%d)\n", pThis->szName, err));
+ return rc;
+}
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ vboxNetFltDarwinAttachToInterface(pThis, true /* fRediscovery */);
+ return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+ int rc = VINF_SUCCESS;
+ ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
+ if (pIfNet)
+ {
+ /*
+ * Create a mbuf for the gather list and push it onto the wire.
+ */
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
+ if (pMBuf)
+ {
+ errno_t err = ifnet_output_raw(pIfNet, PF_LINK, pMBuf);
+ if (err)
+ rc = RTErrConvertFromErrno(err);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ /*
+ * Create a mbuf for the gather list and push it onto the host stack.
+ */
+ if (fDst & INTNETTRUNKDIR_HOST)
+ {
+ mbuf_t pMBuf = vboxNetFltDarwinMBufFromSG(pThis, pSG);
+ if (pMBuf)
+ {
+ /* This is what IONetworkInterface::inputPacket does. */
+ unsigned const cbEthHdr = 14;
+ mbuf_pkthdr_setheader(pMBuf, mbuf_data(pMBuf));
+ mbuf_pkthdr_setlen(pMBuf, mbuf_pkthdr_len(pMBuf) - cbEthHdr);
+ mbuf_setdata(pMBuf, (uint8_t *)mbuf_data(pMBuf) + cbEthHdr, mbuf_len(pMBuf) - cbEthHdr);
+ mbuf_pkthdr_setrcvif(pMBuf, pIfNet); /* will crash without this. */
+
+ errno_t err = ifnet_input(pIfNet, pMBuf, NULL);
+ if (err)
+ rc = RTErrConvertFromErrno(err);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
+ }
+
+ return rc;
+}
+
+
+bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
+{
+ bool fRc = false;
+ ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
+ if (pIfNet)
+ {
+ /* gather the data */
+ uint16_t fIf = ifnet_flags(pIfNet);
+ unsigned cPromisc = VBOX_GET_PCOUNT(pIfNet);
+ bool fSetPromiscuous = ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous);
+ vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
+
+ /* calc the return. */
+ fRc = (fIf & IFF_PROMISC)
+ && cPromisc > fSetPromiscuous;
+ }
+ return fRc;
+}
+
+
+void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
+{
+ *pMac = pThis->u.s.Mac;
+}
+
+
+bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
+{
+ /* ASSUMES that the MAC address never changes. */
+ return pThis->u.s.Mac.au16[0] == pMac->au16[0]
+ && pThis->u.s.Mac.au16[1] == pMac->au16[1]
+ && pThis->u.s.Mac.au16[2] == pMac->au16[2];
+}
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis);
+ if (pIfNet)
+ {
+ /*
+ * This api is a bit weird, the best reference is the code.
+ *
+ * Also, we have a bit or race conditions wrt the maintance of
+ * host the interface promiscuity for vboxNetFltPortOsIsPromiscuous.
+ */
+ unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pIfNet);
+ u_int16_t fIf;
+ if (fActive)
+ {
+ Assert(!pThis->u.s.fSetPromiscuous);
+ errno_t err = ENETDOWN;
+ ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, true);
+
+ /*
+ * Try bring the interface up and running if it's down.
+ */
+ fIf = ifnet_flags(pIfNet);
+ if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
+ {
+ err = ifnet_set_flags(pIfNet, IFF_UP, IFF_UP);
+ errno_t err2 = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
+ if (!err)
+ err = err2;
+ fIf = ifnet_flags(pIfNet);
+ }
+
+ /*
+ * Is it already up? If it isn't, leave it to the link event or
+ * we'll upset if_pcount (as stated above, ifnet_set_promiscuous is weird).
+ */
+ if ((fIf & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
+ {
+ err = ifnet_set_promiscuous(pIfNet, 1);
+ pThis->u.s.fSetPromiscuous = err == 0;
+ if (!err)
+ {
+ ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
+
+ /* check if it actually worked, this stuff is not always behaving well. */
+ if (!(ifnet_flags(pIfNet) & IFF_PROMISC))
+ {
+ err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC);
+ if (!err)
+ err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL);
+ if (!err)
+ Log(("vboxNetFlt: fixed IFF_PROMISC on %s (%d->%d)\n", pThis->szName, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ else
+ Log(("VBoxNetFlt: failed to fix IFF_PROMISC on %s, err=%d (%d->%d)\n",
+ pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ }
+ else
+ Log(("VBoxNetFlt: ifnet_set_promiscuous -> err=%d grr! (%d->%d)\n", err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else if (!err)
+ Log(("VBoxNetFlt: Waiting for the link to come up... (%d->%d)\n", cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ if (err)
+ LogRel(("VBoxNetFlt: Failed to put '%s' into promiscuous mode, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ }
+ else
+ {
+ ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false);
+ if (pThis->u.s.fSetPromiscuous)
+ {
+ errno_t err = ifnet_set_promiscuous(pIfNet, 0);
+ AssertMsg(!err, ("%d\n", err)); NOREF(err);
+ }
+ pThis->u.s.fSetPromiscuous = false;
+
+ fIf = ifnet_flags(pIfNet);
+ Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet)));
+ }
+
+ vboxNetFltDarwinReleaseIfNet(pThis, pIfNet);
+ }
+}
+
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ interface_filter_t pIfFilter;
+
+ /*
+ * Carefully obtain the interface filter reference and detach it.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ pIfFilter = (interface_filter_t)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pIfFilter);
+ if (pIfFilter)
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pIfFilter, NULL);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ if (pIfFilter)
+ iflt_detach(pIfFilter);
+}
+
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
+{
+ return vboxNetFltDarwinAttachToInterface(pThis, false /* fRediscovery */);
+}
+
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ /*
+ * Init the darwin specific members.
+ */
+ pThis->u.s.pIfNet = NULL;
+ pThis->u.s.pIfFilter = NULL;
+ pThis->u.s.fSetPromiscuous = false;
+ pThis->u.s.fNeedSetPromiscuous = false;
+ //pThis->u.s.Mac = {0};
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/darwin/loadnetflt.sh b/src/VBox/HostDrivers/VBoxNetFlt/darwin/loadnetflt.sh
new file mode 100755
index 000000000..810189ab7
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/darwin/loadnetflt.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+## @file
+# For development.
+#
+
+#
+# Copyright (C) 2006-2008 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SCRIPT_NAME="loadusb"
+XNU_VERSION=`LC_ALL=C uname -r | LC_ALL=C cut -d . -f 1`
+
+DRVNAME="VBoxNetFlt.kext"
+BUNDLE="org.virtualbox.kext.VBoxNetFlt"
+
+if [ "$XNU_VERSION" -ge "9" ]; then
+ DEP_DRVNAME="VBoxDrv.kext"
+else
+ DEP_DRVNAME="VBoxDrvTiger.kext"
+fi
+DEP_BUNDLE="org.virtualbox.kext.VBoxDrv"
+
+
+DIR=`dirname "$0"`
+DIR=`cd "$DIR" && pwd`
+DEP_DIR="$DIR/$DEP_DRVNAME"
+DIR="$DIR/$DRVNAME"
+if [ ! -d "$DIR" ]; then
+ echo "Cannot find $DIR or it's not a directory..."
+ exit 1;
+fi
+if [ ! -d "$DEP_DIR" ]; then
+ echo "Cannot find $DEP_DIR or it's not a directory... (dependency)"
+ exit 1;
+fi
+if [ -n "$*" ]; then
+ OPTS="$*"
+else
+ OPTS="-t"
+fi
+
+trap "sudo chown -R `whoami` $DIR $DEP_DIR; exit 1" INT
+
+# Try unload any existing instance first.
+LOADED=`kextstat -b $BUNDLE -l`
+if test -n "$LOADED"; then
+ echo "${SCRIPT_NAME}.sh: Unloading $BUNDLE..."
+ sudo kextunload -v 6 -b $BUNDLE
+ LOADED=`kextstat -b $BUNDLE -l`
+ if test -n "$LOADED"; then
+ echo "${SCRIPT_NAME}.sh: failed to unload $BUNDLE, see above..."
+ exit 1;
+ fi
+ echo "${SCRIPT_NAME}.sh: Successfully unloaded $BUNDLE"
+fi
+
+set -e
+
+# Copy the .kext to the symbols directory and tweak the kextload options.
+if test -n "$VBOX_DARWIN_SYMS"; then
+ echo "${SCRIPT_NAME}.sh: copying the extension the symbol area..."
+ rm -Rf "$VBOX_DARWIN_SYMS/$DRVNAME"
+ mkdir -p "$VBOX_DARWIN_SYMS"
+ cp -R "$DIR" "$VBOX_DARWIN_SYMS/"
+ OPTS="$OPTS -s $VBOX_DARWIN_SYMS/ "
+ sync
+fi
+
+# On smbfs, this might succeed just fine but make no actual changes,
+# so we might have to temporarily copy the driver to a local directory.
+sudo chown -R root:wheel "$DIR" "$DEP_DIR"
+OWNER=`/usr/bin/stat -f "%u" "$DIR"`
+if test "$OWNER" -ne 0; then
+ TMP_DIR=/tmp/${SCRIPT_NAME}.tmp
+ echo "${SCRIPT_NAME}.sh: chown didn't work on $DIR, using temp location $TMP_DIR/$DRVNAME"
+
+ # clean up first (no sudo rm)
+ if test -e "$TMP_DIR"; then
+ sudo chown -R `whoami` "$TMP_DIR"
+ rm -Rf "$TMP_DIR"
+ fi
+
+ # make a copy and switch over DIR
+ mkdir -p "$TMP_DIR/"
+ sudo cp -Rp "$DIR" "$TMP_DIR/"
+ DIR="$TMP_DIR/$DRVNAME"
+
+ # load.sh puts it here.
+ DEP_DIR="/tmp/loaddrv.tmp/$DEP_DRVNAME"
+
+ # retry
+ sudo chown -R root:wheel "$DIR" "$DEP_DIR"
+fi
+
+sudo chmod -R o-rwx "$DIR"
+sync
+echo "${SCRIPT_NAME}.sh: loading $DIR... (kextload $OPTS \"$DIR\")"
+sudo kextload $OPTS -d "$DEP_DIR" "$DIR"
+sync
+sudo chown -R `whoami` "$DIR" "$DEP_DIR"
+kextstat | grep org.virtualbox.kext
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile b/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile
new file mode 100644
index 000000000..0f7b05556
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile
@@ -0,0 +1,264 @@
+#
+# Makefile for the VirtualBox Linux Host Network Filter Driver.
+# (For 2.6.x this file must be called 'Makefile'!)
+#
+
+#
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+#
+# First, figure out which architecture we're targeting and the build type.
+# (We have to support basic cross building (ARCH=i386|x86_64).)
+# While at it, warn about BUILD_* vars found to help with user problems.
+#
+ifneq ($(filter-out amd64 x86,$(BUILD_TARGET_ARCH)),)
+ $(warning Ignoring unknown BUILD_TARGET_ARCH value '$(BUILD_TARGET_ARCH)'.)
+ BUILD_TARGET_ARCH :=
+endif
+ifeq ($(BUILD_TARGET_ARCH),)
+ ifeq ($(ARCH),x86_64)
+ BUILD_TARGET_ARCH := amd64
+ else
+ ifeq ($(ARCH),i386)
+ BUILD_TARGET_ARCH := x86
+ else
+ ifeq ($(filter-out x86_64 amd64 AMD64,$(shell uname -m)),)
+ BUILD_TARGET_ARCH := amd64
+ else
+ BUILD_TARGET_ARCH := x86
+ endif
+ endif
+ endif
+else
+ $(warning Using BUILD_TARGET_ARCH='$(BUILD_TARGET_ARCH)' from the $(origin BUILD_TARGET_ARCH).)
+endif
+
+ifneq ($(filter-out release profile debug strict,$(BUILD_TYPE)),)
+ $(warning Ignoring unknown BUILD_TYPE value '$(BUILD_TYPE)'.)
+ BUILD_TYPE :=
+endif
+ifeq ($(BUILD_TYPE),)
+ BUILD_TYPE := release
+else
+ $(warning Using BUILD_TYPE='$(BUILD_TYPE)' from the $(origin BUILD_TYPE).)
+endif
+
+# override is required by the Debian guys
+override MODULE = vboxnetflt
+OBJS = \
+ linux/VBoxNetFlt-linux.o \
+ VBoxNetFlt.o \
+ SUPR0IdcClient.o \
+ SUPR0IdcClientComponent.o \
+ SUPR0IdcClient-linux.o \
+ r0drv/alloc-r0drv.o \
+ r0drv/initterm-r0drv.o \
+ r0drv/memobj-r0drv.o \
+ r0drv/mpnotification-r0drv.o \
+ r0drv/powernotification-r0drv.o \
+ r0drv/linux/assert-r0drv-linux.o \
+ r0drv/linux/alloc-r0drv-linux.o \
+ r0drv/linux/initterm-r0drv-linux.o \
+ r0drv/linux/memobj-r0drv-linux.o \
+ r0drv/linux/mp-r0drv-linux.o \
+ r0drv/linux/mpnotification-r0drv-linux.o \
+ r0drv/linux/process-r0drv-linux.o \
+ r0drv/linux/semevent-r0drv-linux.o \
+ r0drv/linux/semeventmulti-r0drv-linux.o \
+ r0drv/linux/semfastmutex-r0drv-linux.o \
+ r0drv/linux/spinlock-r0drv-linux.o \
+ r0drv/linux/thread-r0drv-linux.o \
+ r0drv/linux/thread2-r0drv-linux.o \
+ r0drv/linux/time-r0drv-linux.o \
+ common/err/RTErrConvertFromErrno.o \
+ common/err/RTErrConvertToErrno.o \
+ common/log/log.o \
+ common/log/logellipsis.o \
+ common/log/logrel.o \
+ common/log/logrelellipsis.o \
+ common/log/logcom.o \
+ common/log/logformat.o \
+ common/string/strformat.o \
+ common/string/strformatrt.o \
+ common/string/strformattype.o \
+ common/string/strprintf.o \
+ common/string/strtonum.o \
+ r0drv/linux/RTLogWriteDebugger-r0drv-linux.o \
+ generic/RTAssertShouldPanic-generic.o \
+ generic/RTLogWriteStdErr-stub-generic.o \
+ generic/RTLogWriteStdOut-stub-generic.o \
+ generic/RTLogWriteUser-generic.o \
+ generic/uuid-generic.o \
+ VBox/log-vbox.o \
+ VBox/strformat-vbox.o
+ifeq ($(BUILD_TARGET_ARCH),x86)
+OBJS += math/gcc/divdi3.o \
+ math/gcc/moddi3.o \
+ math/gcc/qdivrem.o \
+ math/gcc/udivdi3.o \
+ math/gcc/divdi3.o \
+ math/gcc/umoddi3.o
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+OBJS += alloc/heapsimple.o
+endif
+
+ifneq ($(MAKECMDGOALS),clean)
+
+ifeq ($(KERNELRELEASE),)
+
+ #
+ # building from this directory
+ #
+
+ # kernel base directory
+ ifndef KERN_DIR
+ # build for the current kernel, version check
+ KERN_DIR := /lib/modules/$(shell uname -r)/build
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ KERN_DIR := /usr/src/linux
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: unable to find the sources of your current Linux kernel. \
+ Specify KERN_DIR=<directory> and run Make again)
+ endif
+ $(warning Warning: using /usr/src/linux as the source directory of your \
+ Linux kernel. If this is not correct, specify \
+ KERN_DIR=<directory> and run Make again.)
+ endif
+ # check if versions match -- works only for later 2.6 kernels
+ VBOX_KERN_VER := $(shell $(MAKE) -sC $(KERN_DIR) kernelrelease 2> /dev/null || true)
+ ifneq ($(VBOX_KERN_VER),)
+ ifneq ($(VBOX_KERN_VER),$(shell uname -r))
+ $(error Error: /usr/src/linux (version $(VBOX_KERN_VER)) does not match \
+ the current kernel (version $(shell uname -r)))
+ endif
+ endif
+ else
+ # build for a dedicated kernel, no version check
+ ifneq ($(shell if test -d $(KERN_DIR); then echo yes; fi),yes)
+ $(error Error: KERN_DIR does not point to a directory)
+ endif
+ endif
+
+ # includes
+ ifndef KERN_INCL
+ KERN_INCL = $(KERN_DIR)/include
+ endif
+ ifneq ($(shell if test -d $(KERN_INCL); then echo yes; fi),yes)
+ $(error Error: unable to find the include directory for your current Linux \
+ kernel. Specify KERN_INCL=<directory> and run Make again)
+ endif
+
+ # module install dir, only for current kernel
+ ifneq ($(filter install install_rpm,$(MAKECMDGOALS)),)
+ ifndef MODULE_DIR
+ MODULE_DIR_TST := /lib/modules/$(shell uname -r)
+ ifeq ($(shell if test -d $(MODULE_DIR_TST); then echo yes; fi),yes)
+ MODULE_DIR := $(MODULE_DIR_TST)/misc
+ else
+ $(error Unable to find the folder to install the support driver to)
+ endif
+ endif # MODULE_DIR unspecified
+ endif
+
+else # neq($(KERNELRELEASE),)
+
+ #
+ # building from kbuild (make -C <kernel_directory> M=`pwd`)
+ #
+
+endif # neq($(KERNELRELEASE),)
+
+# debug - show guesses.
+ifdef DEBUG
+$(warning dbg: KERN_DIR = $(KERN_DIR))
+$(warning dbg: KERN_INCL = $(KERN_INCL))
+$(warning dbg: MODULE_DIR = $(MODULE_DIR))
+endif
+
+KBUILD_VERBOSE ?= 1
+
+#
+# Compiler options
+#
+ifndef INCL
+ INCL := $(addprefix -I,$(KERN_INCL) $(EXTRA_INCL))
+ ifndef KBUILD_EXTMOD
+ KBUILD_EXTMOD := $(shell pwd)
+ endif
+ INCL += $(addprefix -I$(KBUILD_EXTMOD),/ /include /r0drv/linux)
+ export INCL
+endif
+KFLAGS := -D__KERNEL__ -DMODULE -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 -DIN_SUP_R0 -DVBOX -DRT_WITH_VBOX -DVBOX_WITH_HARDENING
+ifdef VBOX_REDHAT_KABI
+ KFLAGS += -DVBOX_REDHAT_KABI
+endif
+ifeq ($(BUILD_TARGET_ARCH),amd64)
+ KFLAGS += -DRT_ARCH_AMD64
+else
+ KFLAGS += -DRT_ARCH_X86
+endif
+# must be consistent with Config.kmk!
+KFLAGS += -DVBOX_WITH_64_BITS_GUESTS
+ifeq ($(BUILD_TYPE),debug)
+ KFLAGS += -DDEBUG -DDEBUG_$(USER) -g
+ # IPRT_DEBUG_SEMS indicates thread wrt sems state via the comm field.
+ KFLAGS += -DIPRT_DEBUG_SEMS
+endif
+
+# By default we use remap_pfn_range() kernel API to make kernel pages
+# visible for userland. Unfortuately, it leads to situation that
+# during debug session all structures on that page (such as PVM pointer)
+# are not accessible to the debugger (see #3214).
+# This code enables experimental support
+# for vm_insert_page() kernel API, allowing to export kernel pages
+# to the userland in more debugger-friendly way. Due to stability
+# concerns, not enabled by default yet.
+ifdef VBOX_USE_INSERT_PAGE
+ KFLAGS += -DVBOX_USE_INSERT_PAGE
+endif
+
+MODULE_EXT := ko
+$(MODULE)-y := $(OBJS)
+
+# build defs
+EXTRA_CFLAGS += $(INCL) $(KFLAGS) $(KDEBUG)
+
+all: $(MODULE)
+
+obj-m += $(MODULE).o
+
+$(MODULE):
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C $(KERN_DIR) SUBDIRS=$(CURDIR) SRCROOT=$(CURDIR) modules
+
+install: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0664 -o root -g root $(MODULE).$(MODULE_EXT) $(MODULE_DIR); \
+ PATH="$(PATH):/bin:/sbin" depmod -ae; \
+ rm -f /etc/vbox/module_not_compiled
+
+install_rpm: $(MODULE)
+ @mkdir -p $(MODULE_DIR); \
+ install -m 0664 $(MODULE).$(MODULE_EXT) $(MODULE_DIR)
+
+endif # eq($(MAKECMDGOALS),clean)
+
+# important: Don't remove Module.symvers! DKMS does 'make clean' before building ...
+clean:
+ for f in . linux r0drv r0drv/linux VBox common/err common/string common/log generic math/gcc; \
+ do rm -f $$f/*.o $$f/.*.cmd $$f/.*.flags; done
+ rm -rf .vboxnetflt* .tmp_ver* vboxnetflt.* Modules.symvers modules.order
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c b/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
new file mode 100644
index 000000000..ba74ed7f1
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
@@ -0,0 +1,1099 @@
+/* $Id: VBoxNetFlt-linux.c 16098 2009-01-20 19:22:12Z vboxsync $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Linux Specific Code.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "the-linux-kernel.h"
+#include "version-generated.h"
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/mem.h>
+#include <iprt/log.h>
+#include <iprt/mp.h>
+#include <iprt/mem.h>
+#include <iprt/time.h>
+
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "../VBoxNetFltInternal.h"
+
+#define VBOX_FLT_NB_TO_INST(pNB) ((PVBOXNETFLTINS)((uint8_t *)pNB - \
+ RT_OFFSETOF(VBOXNETFLTINS, u.s.Notifier)))
+#define VBOX_FLT_PT_TO_INST(pPT) ((PVBOXNETFLTINS)((uint8_t *)pPT - \
+ RT_OFFSETOF(VBOXNETFLTINS, u.s.PacketType)))
+#define VBOX_FLT_XT_TO_INST(pXT) ((PVBOXNETFLTINS)((uint8_t *)pXT - \
+ RT_OFFSETOF(VBOXNETFLTINS, u.s.XmitTask)))
+
+#define VBOX_GET_PCOUNT(pDev) (pDev->promiscuity)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+# define VBOX_SKB_RESET_NETWORK_HDR(skb) skb_reset_network_header(skb)
+# define VBOX_SKB_RESET_MAC_HDR(skb) skb_reset_mac_header(skb)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
+# define VBOX_SKB_RESET_NETWORK_HDR(skb) skb->nh.raw = skb->data
+# define VBOX_SKB_RESET_MAC_HDR(skb) skb->mac.raw = skb->data
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+# define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */
+# define CHECKSUM_PARTIAL CHECKSUM_HW
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+# define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb, 0)
+# else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
+# define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(&skb, 0)
+# else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */
+# define VBOX_SKB_CHECKSUM_HELP(skb) (!skb_checksum_help(skb))
+# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */
+# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+# define VBOX_SKB_IS_GSO(skb) skb_is_gso(skb)
+ /* No features, very dumb device */
+# define VBOX_SKB_GSO_SEGMENT(skb) skb_gso_segment(skb, 0)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
+# define VBOX_SKB_IS_GSO(skb) false
+# define VBOX_SKB_GSO_SEGMENT(skb) NULL
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
+
+#ifndef NET_IP_ALIGN
+# define NET_IP_ALIGN 2
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+unsigned dev_get_flags(const struct net_device *dev)
+{
+ unsigned flags;
+
+ flags = (dev->flags & ~(IFF_PROMISC |
+ IFF_ALLMULTI |
+ IFF_RUNNING)) |
+ (dev->gflags & (IFF_PROMISC |
+ IFF_ALLMULTI));
+
+ if (netif_running(dev) && netif_carrier_ok(dev))
+ flags |= IFF_RUNNING;
+
+ return flags;
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) */
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int VBoxNetFltLinuxInit(void);
+static void VBoxNetFltLinuxUnload(void);
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * The (common) global data.
+ */
+#ifdef RT_ARCH_AMD64
+/**
+ * Memory for the executable memory heap (in IPRT).
+ */
+extern uint8_t g_abExecMemory[4096]; /* cannot donate less than one page */
+__asm__(".section execmemory, \"awx\", @progbits\n\t"
+ ".align 32\n\t"
+ ".globl g_abExecMemory\n"
+ "g_abExecMemory:\n\t"
+ ".zero 4096\n\t"
+ ".type g_abExecMemory, @object\n\t"
+ ".size g_abExecMemory, 4096\n\t"
+ ".text\n\t");
+#endif
+
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+
+module_init(VBoxNetFltLinuxInit);
+module_exit(VBoxNetFltLinuxUnload);
+
+MODULE_AUTHOR("Sun Microsystems, Inc.");
+MODULE_DESCRIPTION("VirtualBox Network Filter Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+# define xstr(s) str(s)
+# define str(s) #s
+MODULE_VERSION(VBOX_VERSION_STRING " (" xstr(INTNETTRUNKIFPORT_VERSION) ")");
+#endif
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxNetFltLinuxInit(void)
+{
+ int rc;
+ /*
+ * Initialize IPRT.
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+#ifdef RT_ARCH_AMD64
+ rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
+ printk("VBoxNetFlt: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
+ if (RT_FAILURE(rc))
+ {
+ printk("VBoxNetFlt: failed to donate exec memory, no logging will be available.\n");
+ }
+#endif
+ Log(("VBoxNetFltLinuxInit\n"));
+
+ /*
+ * Initialize the globals and connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel(("VBoxNetFlt: Successfully started.\n"));
+ return 0;
+ }
+
+ LogRel(("VBoxNetFlt: failed to initialize device extension (rc=%d)\n", rc));
+ RTR0Term();
+ }
+ else
+ LogRel(("VBoxNetFlt: failed to initialize IPRT (rc=%d)\n", rc));
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ return -RTErrConvertToErrno(rc);
+}
+
+
+/**
+ * Unload the module.
+ *
+ * @todo We have to prevent this if we're busy!
+ */
+static void __exit VBoxNetFltLinuxUnload(void)
+{
+ int rc;
+ Log(("VBoxNetFltLinuxUnload\n"));
+ Assert(vboxNetFltCanUnload(&g_VBoxNetFltGlobals));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltGlobals);
+ AssertRC(rc); NOREF(rc);
+
+ RTR0Term();
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+
+ Log(("VBoxNetFltLinuxUnload - done\n"));
+}
+
+
+/**
+ * Reads and retains the host interface handle.
+ *
+ * @returns The handle, NULL if detached.
+ * @param pThis
+ */
+DECLINLINE(struct net_device *) vboxNetFltLinuxRetainNetDev(PVBOXNETFLTINS pThis)
+{
+#if 0
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ struct net_device *pDev = NULL;
+
+ Log(("vboxNetFltLinuxRetainNetDev\n"));
+ /*
+ * Be careful here to avoid problems racing the detached callback.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ if (!ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
+ {
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ if (pDev)
+ {
+ dev_hold(pDev);
+ Log(("vboxNetFltLinuxRetainNetDev: Device %p(%s) retained. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ }
+ }
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ Log(("vboxNetFltLinuxRetainNetDev - done\n"));
+ return pDev;
+#else
+ return (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+#endif
+}
+
+
+/**
+ * Release the host interface handle previously retained
+ * by vboxNetFltLinuxRetainNetDev.
+ *
+ * @param pThis The instance.
+ * @param pDev The vboxNetFltLinuxRetainNetDev
+ * return value, NULL is fine.
+ */
+DECLINLINE(void) vboxNetFltLinuxReleaseNetDev(PVBOXNETFLTINS pThis, struct net_device *pDev)
+{
+#if 0
+ Log(("vboxNetFltLinuxReleaseNetDev\n"));
+ NOREF(pThis);
+ if (pDev)
+ {
+ dev_put(pDev);
+ Log(("vboxNetFltLinuxReleaseNetDev: Device %p(%s) released. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ }
+ Log(("vboxNetFltLinuxReleaseNetDev - done\n"));
+#endif
+}
+
+#define VBOXNETFLT_CB_TAG 0xA1C9D7C3
+#define VBOXNETFLT_SKB_TAG(skb) (*(uint32_t*)&((skb)->cb[sizeof((skb)->cb)-sizeof(uint32_t)]))
+
+/**
+ * Checks whether this is an mbuf created by vboxNetFltLinuxMBufFromSG,
+ * i.e. a buffer which we're pushing and should be ignored by the filter callbacks.
+ *
+ * @returns true / false accordingly.
+ * @param pBuf The sk_buff.
+ */
+DECLINLINE(bool) vboxNetFltLinuxSkBufIsOur(struct sk_buff *pBuf)
+{
+ return VBOXNETFLT_SKB_TAG(pBuf) == VBOXNETFLT_CB_TAG ;
+}
+
+
+/**
+ * Internal worker that create a linux sk_buff for a
+ * (scatter/)gather list.
+ *
+ * @returns Pointer to the sk_buff.
+ * @param pThis The instance.
+ * @param pSG The (scatter/)gather list.
+ */
+static struct sk_buff *vboxNetFltLinuxSkBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, bool fDstWire)
+{
+ struct sk_buff *pPkt;
+ struct net_device *pDev;
+ /*
+ * Because we're lazy, we will ASSUME that all SGs coming from INTNET
+ * will only contain one single segment.
+ */
+ if (pSG->cSegsUsed != 1 || pSG->cbTotal != pSG->aSegs[0].cb)
+ {
+ LogRel(("VBoxNetFlt: Dropped multi-segment(%d) packet coming from internal network.\n", pSG->cSegsUsed));
+ return NULL;
+ }
+ if (pSG->cbTotal == 0)
+ {
+ LogRel(("VBoxNetFlt: Dropped empty packet coming from internal network.\n"));
+ return NULL;
+ }
+
+ /*
+ * Allocate a packet and copy over the data.
+ *
+ */
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ pPkt = dev_alloc_skb(pSG->cbTotal + NET_IP_ALIGN);
+ if (pPkt)
+ {
+ pPkt->dev = pDev;
+ /* Align IP header on 16-byte boundary: 2 + 14 (ethernet hdr size). */
+ skb_reserve(pPkt, NET_IP_ALIGN);
+ skb_put(pPkt, pSG->cbTotal);
+ memcpy(pPkt->data, pSG->aSegs[0].pv, pSG->cbTotal);
+ /* Set protocol and packet_type fields. */
+ pPkt->protocol = eth_type_trans(pPkt, pDev);
+ pPkt->ip_summed = CHECKSUM_NONE;
+ if (fDstWire)
+ {
+ VBOX_SKB_RESET_NETWORK_HDR(pPkt);
+ /* Restore ethernet header back. */
+ skb_push(pPkt, ETH_HLEN);
+ VBOX_SKB_RESET_MAC_HDR(pPkt);
+ }
+ VBOXNETFLT_SKB_TAG(pPkt) = VBOXNETFLT_CB_TAG;
+
+ return pPkt;
+ }
+ else
+ Log(("vboxNetFltLinuxSkBufFromSG: Failed to allocate sk_buff(%u).\n", pSG->cbTotal));
+ pSG->pvUserData = NULL;
+
+ return NULL;
+}
+
+
+/**
+ * Initializes a SG list from an sk_buff.
+ *
+ * @returns Number of segments.
+ * @param pThis The instance.
+ * @param pBuf The sk_buff.
+ * @param pSG The SG.
+ * @param pvFrame The frame pointer, optional.
+ * @param cSegs The number of segments allocated for the SG.
+ * This should match the number in the mbuf exactly!
+ * @param fSrc The source of the frame.
+ */
+DECLINLINE(void) vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
+{
+ int i;
+ NOREF(pThis);
+
+ Assert(!skb_shinfo(pBuf)->frag_list);
+ pSG->pvOwnerData = NULL;
+ pSG->pvUserData = NULL;
+ pSG->pvUserData2 = NULL;
+ pSG->cUsers = 1;
+ pSG->fFlags = INTNETSG_FLAGS_TEMP;
+ pSG->cSegsAlloc = cSegs;
+
+ if (fSrc & INTNETTRUNKDIR_WIRE)
+ {
+ /*
+ * The packet came from wire, ethernet header was removed by device driver.
+ * Restore it.
+ */
+ skb_push(pBuf, ETH_HLEN);
+ }
+ pSG->cbTotal = pBuf->len;
+#ifdef VBOXNETFLT_SG_SUPPORT
+ pSG->aSegs[0].cb = skb_headlen(pBuf);
+ pSG->aSegs[0].pv = pBuf->data;
+ pSG->aSegs[0].Phys = NIL_RTHCPHYS;
+
+ for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++)
+ {
+ skb_frag_t *pFrag = &skb_shinfo(pBuf)->frags[i];
+ pSG->aSegs[i+1].cb = pFrag->size;
+ pSG->aSegs[i+1].pv = kmap(pFrag->page);
+ printk("%p = kmap()\n", pSG->aSegs[i+1].pv);
+ pSG->aSegs[i+1].Phys = NIL_RTHCPHYS;
+ }
+ pSG->cSegsUsed = ++i;
+#else
+ pSG->aSegs[0].cb = pBuf->len;
+ pSG->aSegs[0].pv = pBuf->data;
+ pSG->aSegs[0].Phys = NIL_RTHCPHYS;
+ pSG->cSegsUsed = i = 1;
+#endif
+
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ /*
+ * Add a trailer if the frame is too small.
+ *
+ * Since we're getting to the packet before it is framed, it has not
+ * yet been padded. The current solution is to add a segment pointing
+ * to a buffer containing all zeros and pray that works for all frames...
+ */
+ if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
+ {
+ static uint8_t const s_abZero[128] = {0};
+
+ AssertReturnVoid(i < cSegs);
+
+ pSG->aSegs[i].Phys = NIL_RTHCPHYS;
+ pSG->aSegs[i].pv = (void *)&s_abZero[0];
+ pSG->aSegs[i].cb = 60 - pSG->cbTotal;
+ pSG->cbTotal = 60;
+ pSG->cSegsUsed++;
+ }
+#endif
+ Log4(("vboxNetFltLinuxSkBufToSG: allocated=%d, segments=%d frags=%d next=%p frag_list=%p pkt_type=%x fSrc=%x\n",
+ pSG->cSegsAlloc, pSG->cSegsUsed, skb_shinfo(pBuf)->nr_frags, pBuf->next, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, fSrc));
+ for (i = 0; i < pSG->cSegsUsed; i++)
+ Log4(("vboxNetFltLinuxSkBufToSG: #%d: cb=%d pv=%p\n",
+ i, pSG->aSegs[i].cb, pSG->aSegs[i].pv));
+}
+
+/**
+ * Packet handler,
+ *
+ * @returns 0 or EJUSTRETURN.
+ * @param pThis The instance.
+ * @param pMBuf The mbuf.
+ * @param pvFrame The start of the frame, optional.
+ * @param fSrc Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value.
+ * @param eProtocol The protocol.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
+static int vboxNetFltLinuxPacketHandler(struct sk_buff *pBuf,
+ struct net_device *pSkbDev,
+ struct packet_type *pPacketType,
+ struct net_device *pOrigDev)
+#else
+static int vboxNetFltLinuxPacketHandler(struct sk_buff *pBuf,
+ struct net_device *pSkbDev,
+ struct packet_type *pPacketType)
+#endif
+{
+ PVBOXNETFLTINS pThis;
+ struct net_device *pDev;
+ LogFlow(("vboxNetFltLinuxPacketHandler: pBuf=%p pSkbDev=%p pPacketType=%p\n",
+ pBuf, pSkbDev, pPacketType));
+ /*
+ * Drop it immediately?
+ */
+ if (!pBuf)
+ return 0;
+
+ pThis = VBOX_FLT_PT_TO_INST(pPacketType);
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ if (pThis->u.s.pDev != pSkbDev)
+ {
+ Log(("vboxNetFltLinuxPacketHandler: Devices do not match, pThis may be wrong! pThis=%p\n", pThis));
+ return 0;
+ }
+
+ Log4(("vboxNetFltLinuxPacketHandler: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
+ if (vboxNetFltLinuxSkBufIsOur(pBuf))
+ {
+ Log2(("vboxNetFltLinuxPacketHandler: got our own sk_buff, drop it.\n"));
+ dev_kfree_skb(pBuf);
+ return 0;
+ }
+
+#ifndef VBOXNETFLT_SG_SUPPORT
+ {
+ /*
+ * Get rid of fragmented packets, they cause too much trouble.
+ */
+ struct sk_buff *pCopy = skb_copy(pBuf, GFP_ATOMIC);
+ kfree_skb(pBuf);
+ if (!pCopy)
+ {
+ LogRel(("VBoxNetFlt: Failed to allocate packet buffer, dropping the packet.\n"));
+ return 0;
+ }
+ pBuf = pCopy;
+ }
+#endif
+
+ /* Add the packet to transmit queue and schedule the bottom half. */
+ skb_queue_tail(&pThis->u.s.XmitQueue, pBuf);
+ schedule_work(&pThis->u.s.XmitTask);
+ Log4(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n",
+ &pThis->u.s.XmitTask, pBuf));
+ /* It does not really matter what we return, it is ignored by the kernel. */
+ return 0;
+}
+
+static unsigned vboxNetFltLinuxSGSegments(PVBOXNETFLTINS pThis, struct sk_buff *pBuf)
+{
+#ifdef VBOXNETFLT_SG_SUPPORT
+ unsigned cSegs = 1 + skb_shinfo(pBuf)->nr_frags;
+#else
+ unsigned cSegs = 1;
+#endif
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ /*
+ * Add a trailer if the frame is too small.
+ */
+ if (pBuf->len < 60)
+ cSegs++;
+#endif
+ return cSegs;
+}
+
+/* WARNING! This function should only be called after vboxNetFltLinuxSkBufToSG()! */
+static void vboxNetFltLinuxFreeSkBuff(struct sk_buff *pBuf, PINTNETSG pSG)
+{
+#ifdef VBOXNETFLT_SG_SUPPORT
+ int i;
+
+ for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++)
+ {
+ printk("kunmap(%p)\n", pSG->aSegs[i+1].pv);
+ kunmap(pSG->aSegs[i+1].pv);
+ }
+#endif
+
+ dev_kfree_skb(pBuf);
+}
+
+#ifndef LOG_ENABLED
+#define vboxNetFltDumpPacket(a, b, c, d)
+#else
+static void vboxNetFltDumpPacket(PINTNETSG pSG, bool fEgress, const char *pszWhere, int iIncrement)
+{
+ uint8_t *pInt, *pExt;
+ static int iPacketNo = 1;
+ iPacketNo += iIncrement;
+ if (fEgress)
+ {
+ pExt = pSG->aSegs[0].pv;
+ pInt = pExt + 6;
+ }
+ else
+ {
+ pInt = pSG->aSegs[0].pv;
+ pExt = pInt + 6;
+ }
+ Log(("VBoxNetFlt: (int)%02x:%02x:%02x:%02x:%02x:%02x"
+ " %s (%s)%02x:%02x:%02x:%02x:%02x:%02x (%u bytes) packet #%u\n",
+ pInt[0], pInt[1], pInt[2], pInt[3], pInt[4], pInt[5],
+ fEgress ? "-->" : "<--", pszWhere,
+ pExt[0], pExt[1], pExt[2], pExt[3], pExt[4], pExt[5],
+ pSG->cbTotal, iPacketNo));
+ Log3(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv));
+}
+#endif
+
+static int vboxNetFltLinuxForwardSegment(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc)
+{
+ unsigned cSegs = vboxNetFltLinuxSGSegments(pThis, pBuf);
+ if (cSegs < MAX_SKB_FRAGS)
+ {
+ uint8_t *pTmp;
+ PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ if (!pSG)
+ {
+ Log(("VBoxNetFlt: Failed to allocate SG buffer.\n"));
+ return VERR_NO_MEMORY;
+ }
+ vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc);
+
+ pTmp = pSG->aSegs[0].pv;
+ vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
+ pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
+ Log4(("VBoxNetFlt: Dropping the sk_buff.\n"));
+ vboxNetFltLinuxFreeSkBuff(pBuf, pSG);
+ }
+
+ return VINF_SUCCESS;
+}
+
+static void vboxNetFltLinuxForwardToIntNet(PVBOXNETFLTINS pThis, struct sk_buff *pBuf)
+{
+ uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE;
+
+ if (VBOX_SKB_IS_GSO(pBuf))
+ {
+ /* Need to segment the packet */
+ struct sk_buff *pNext, *pSegment;
+ //Log2(("vboxNetFltLinuxForwardToIntNet: cb=%u gso_size=%u gso_segs=%u gso_type=%u\n",
+ // pBuf->len, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type));
+
+ for (pSegment = VBOX_SKB_GSO_SEGMENT(pBuf); pSegment; pSegment = pNext)
+ {
+ pNext = pSegment->next;
+ pSegment->next = 0;
+ vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc);
+ }
+ dev_kfree_skb(pBuf);
+ }
+ else
+ {
+ if (pBuf->ip_summed == CHECKSUM_PARTIAL)
+ if (VBOX_SKB_CHECKSUM_HELP(pBuf))
+ {
+ LogRel(("VBoxNetFlt: Failed to compute checksum, dropping the packet.\n"));
+ dev_kfree_skb(pBuf);
+ return;
+ }
+ vboxNetFltLinuxForwardSegment(pThis, pBuf, fSrc);
+ }
+ /*
+ * Create a (scatter/)gather list for the sk_buff and feed it to the internal network.
+ */
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+static void vboxNetFltLinuxXmitTask(struct work_struct *pWork)
+#else
+static void vboxNetFltLinuxXmitTask(void *pWork)
+#endif
+{
+ struct sk_buff *pBuf;
+ bool fActive;
+ PVBOXNETFLTINS pThis;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+ Log4(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork));
+ pThis = VBOX_FLT_XT_TO_INST(pWork);
+ /*
+ * Active? Retain the instance and increment the busy counter.
+ */
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fActive)
+ vboxNetFltRetain(pThis, true /* fBusy */);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ if (!fActive)
+ return;
+
+ while ((pBuf = skb_dequeue(&pThis->u.s.XmitQueue)) != 0)
+ vboxNetFltLinuxForwardToIntNet(pThis, pBuf);
+
+ vboxNetFltRelease(pThis, true /* fBusy */);
+}
+
+/**
+ * Internal worker for vboxNetFltOsInitInstance and vboxNetFltOsMaybeRediscovered.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param fRediscovery If set we're doing a rediscovery attempt, so, don't
+ * flood the release log.
+ */
+static int vboxNetFltLinuxAttachToInterface(PVBOXNETFLTINS pThis, struct net_device *pDev)
+{
+ struct packet_type *pt;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+ LogFlow(("vboxNetFltLinuxAttachToInterface: pThis=%p (%s)\n", pThis, pThis->szName));
+
+ if (!pDev)
+ {
+ Log(("VBoxNetFlt: failed to find device '%s'\n", pThis->szName));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+ }
+
+ dev_hold(pDev);
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pDev, pDev);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ Log(("vboxNetFltLinuxAttachToInterface: Device %p(%s) retained. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ Log(("vboxNetFltLinuxAttachToInterface: Got pDev=%p pThis=%p pThis->u.s.pDev=%p\n", pDev, pThis, ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev)));
+ /*
+ * Get the mac address while we still have a valid ifnet reference.
+ */
+ memcpy(&pThis->u.s.Mac, pDev->dev_addr, sizeof(pThis->u.s.Mac));
+
+ pt = &pThis->u.s.PacketType;
+ pt->type = __constant_htons(ETH_P_ALL);
+ pt->dev = pDev;
+ pt->func = vboxNetFltLinuxPacketHandler;
+ dev_add_pack(pt);
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ if (pDev)
+ {
+ ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ ASMAtomicUoWriteBool(&pThis->u.s.fRegistered, true);
+ pDev = NULL; /* don't dereference it */
+ }
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ Log(("vboxNetFltLinuxAttachToInterface: this=%p: Packet handler installed.\n", pThis));
+
+ /* Release the interface on failure. */
+ if (pDev)
+ {
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pDev, NULL);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ dev_put(pDev);
+ Log(("vboxNetFltLinuxAttachToInterface: Device %p(%s) released. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ }
+
+ LogRel(("VBoxNetFlt: attached to '%s' / %.*Rhxs\n", pThis->szName, sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
+ return VINF_SUCCESS;
+}
+
+
+static int vboxNetFltLinuxUnregisterDevice(PVBOXNETFLTINS pThis, struct net_device *pDev)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+ Assert(!pThis->fDisconnectedFromHost);
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ ASMAtomicWriteBool(&pThis->u.s.fRegistered, false);
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
+ ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pDev, NULL);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ dev_remove_pack(&pThis->u.s.PacketType);
+ skb_queue_purge(&pThis->u.s.XmitQueue);
+ Log(("vboxNetFltLinuxUnregisterDevice: this=%p: Packet handler removed, xmit queue purged.\n", pThis));
+ Log(("vboxNetFltLinuxUnregisterDevice: Device %p(%s) released. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ dev_put(pDev);
+
+ return NOTIFY_OK;
+}
+
+static int vboxNetFltLinuxDeviceIsUp(PVBOXNETFLTINS pThis, struct net_device *pDev)
+{
+ /* Check if we are not suspended and promiscuous mode has not been set. */
+ if (ASMAtomicUoReadBool(&pThis->fActive) && !ASMAtomicUoReadBool(&pThis->u.s.fPromiscuousSet))
+ {
+ /* Note that there is no need for locking as the kernel got hold of the lock already. */
+ dev_set_promiscuity(pDev, 1);
+ ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, true);
+ Log(("vboxNetFltLinuxDeviceIsUp: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+ }
+ else
+ Log(("vboxNetFltLinuxDeviceIsUp: no need to enable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+ return NOTIFY_OK;
+}
+
+static int vboxNetFltLinuxDeviceGoingDown(PVBOXNETFLTINS pThis, struct net_device *pDev)
+{
+ /* Undo promiscuous mode if we has set it. */
+ if (ASMAtomicUoReadBool(&pThis->u.s.fPromiscuousSet))
+ {
+ /* Note that there is no need for locking as the kernel got hold of the lock already. */
+ dev_set_promiscuity(pDev, -1);
+ ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, false);
+ Log(("vboxNetFltLinuxDeviceGoingDown: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+ }
+ else
+ Log(("vboxNetFltLinuxDeviceGoingDown: no need to disable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+ return NOTIFY_OK;
+}
+
+static int vboxNetFltLinuxNotifierCallback(struct notifier_block *self, unsigned long ulEventType, void *ptr)
+
+{
+ int rc = NOTIFY_OK;
+#ifdef DEBUG
+ char *pszEvent = "<unknown>";
+#endif
+ struct net_device *pDev = (struct net_device *)ptr;
+ PVBOXNETFLTINS pThis = VBOX_FLT_NB_TO_INST(self);
+
+#ifdef DEBUG
+ switch (ulEventType)
+ {
+ case NETDEV_REGISTER: pszEvent = "NETDEV_REGISTER"; break;
+ case NETDEV_UNREGISTER: pszEvent = "NETDEV_UNREGISTER"; break;
+ case NETDEV_UP: pszEvent = "NETDEV_UP"; break;
+ case NETDEV_DOWN: pszEvent = "NETDEV_DOWN"; break;
+ case NETDEV_REBOOT: pszEvent = "NETDEV_REBOOT"; break;
+ case NETDEV_CHANGENAME: pszEvent = "NETDEV_CHANGENAME"; break;
+ case NETDEV_CHANGE: pszEvent = "NETDEV_CHANGE"; break;
+ case NETDEV_CHANGEMTU: pszEvent = "NETDEV_CHANGEMTU"; break;
+ case NETDEV_CHANGEADDR: pszEvent = "NETDEV_CHANGEADDR"; break;
+ case NETDEV_GOING_DOWN: pszEvent = "NETDEV_GOING_DOWN"; break;
+ }
+ Log(("VBoxNetFlt: got event %s(0x%lx) on %s, pDev=%p pThis=%p pThis->u.s.pDev=%p\n",
+ pszEvent, ulEventType, pDev->name, pDev, pThis, ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev)));
+#endif
+ if (ulEventType == NETDEV_REGISTER && !strcmp(pDev->name, pThis->szName))
+ {
+ vboxNetFltLinuxAttachToInterface(pThis, pDev);
+ }
+ else
+ {
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ if (pDev != ptr)
+ return NOTIFY_OK;
+ rc = NOTIFY_OK;
+ switch (ulEventType)
+ {
+ case NETDEV_UNREGISTER:
+ rc = vboxNetFltLinuxUnregisterDevice(pThis, pDev);
+ break;
+ case NETDEV_UP:
+ rc = vboxNetFltLinuxDeviceIsUp(pThis, pDev);
+ break;
+ case NETDEV_GOING_DOWN:
+ rc = vboxNetFltLinuxDeviceGoingDown(pThis, pDev);
+ break;
+ case NETDEV_CHANGENAME:
+ break;
+ }
+ }
+
+ return rc;
+}
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+ struct net_device * pDev;
+ int err;
+ int rc = VINF_SUCCESS;
+
+ LogFlow(("vboxNetFltPortOsXmit: pThis=%p (%s)\n", pThis, pThis->szName));
+
+ pDev = vboxNetFltLinuxRetainNetDev(pThis);
+ if (pDev)
+ {
+ /*
+ * Create a sk_buff for the gather list and push it onto the wire.
+ */
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ struct sk_buff *pBuf = vboxNetFltLinuxSkBufFromSG(pThis, pSG, true);
+ if (pBuf)
+ {
+ vboxNetFltDumpPacket(pSG, true, "wire", 1);
+ Log4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
+ Log4(("vboxNetFltPortOsXmit: dev_queue_xmit(%p)\n", pBuf));
+ err = dev_queue_xmit(pBuf);
+ if (err)
+ rc = RTErrConvertFromErrno(err);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ /*
+ * Create a sk_buff for the gather list and push it onto the host stack.
+ */
+ if (fDst & INTNETTRUNKDIR_HOST)
+ {
+ struct sk_buff *pBuf = vboxNetFltLinuxSkBufFromSG(pThis, pSG, false);
+ if (pBuf)
+ {
+ vboxNetFltDumpPacket(pSG, true, "host", (fDst & INTNETTRUNKDIR_WIRE) ? 0 : 1);
+ Log4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
+ Log4(("vboxNetFltPortOsXmit: netif_rx_ni(%p)\n", pBuf));
+ err = netif_rx_ni(pBuf);
+ if (err)
+ rc = RTErrConvertFromErrno(err);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ vboxNetFltLinuxReleaseNetDev(pThis, pDev);
+ }
+
+ return rc;
+}
+
+
+bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
+{
+ bool fRc = false;
+ struct net_device * pDev = vboxNetFltLinuxRetainNetDev(pThis);
+ if (pDev)
+ {
+ fRc = !!(pDev->promiscuity - (ASMAtomicUoReadBool(&pThis->u.s.fPromiscuousSet) & 1));
+ LogFlow(("vboxNetFltPortOsIsPromiscuous: returns %d, pDev->promiscuity=%d, fPromiscuousSet=%d\n",
+ fRc, pDev->promiscuity, pThis->u.s.fPromiscuousSet));
+ vboxNetFltLinuxReleaseNetDev(pThis, pDev);
+ }
+ return fRc;
+}
+
+
+void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
+{
+ *pMac = pThis->u.s.Mac;
+}
+
+
+bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
+{
+ /* ASSUMES that the MAC address never changes. */
+ return pThis->u.s.Mac.au16[0] == pMac->au16[0]
+ && pThis->u.s.Mac.au16[1] == pMac->au16[1]
+ && pThis->u.s.Mac.au16[2] == pMac->au16[2];
+}
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ struct net_device * pDev;
+
+ LogFlow(("vboxNetFltPortOsSetActive: pThis=%p (%s), fActive=%s\n",
+ pThis, pThis->szName, fActive?"true":"false"));
+
+ pDev = vboxNetFltLinuxRetainNetDev(pThis);
+ if (pDev)
+ {
+ /*
+ * This api is a bit weird, the best reference is the code.
+ *
+ * Also, we have a bit or race conditions wrt the maintance of
+ * host the interface promiscuity for vboxNetFltPortOsIsPromiscuous.
+ */
+ u_int16_t fIf;
+#ifdef LOG_ENABLED
+ unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pDev);
+#endif
+ if (fActive)
+ {
+ Assert(!pThis->u.s.fPromiscuousSet);
+
+#if 0
+ /*
+ * Try bring the interface up and running if it's down.
+ */
+ fIf = dev_get_flags(pDev);
+ if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
+ {
+ rtnl_lock();
+ int err = dev_change_flags(pDev, fIf | IFF_UP);
+ rtnl_unlock();
+ fIf = dev_get_flags(pDev);
+ }
+
+ /*
+ * Is it already up? If it isn't, leave it to the link event or
+ * we'll upset if_pcount (as stated above, ifnet_set_promiscuous is weird).
+ */
+ if ((fIf & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)
+ && !ASMAtomicReadBool(&pThis->u.s.fPromiscuousSet))
+ {
+#endif
+ rtnl_lock();
+ dev_set_promiscuity(pDev, 1);
+ rtnl_unlock();
+ pThis->u.s.fPromiscuousSet = true;
+ Log(("vboxNetFltPortOsSetActive: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+#if 0
+ /* check if it actually worked, this stuff is not always behaving well. */
+ if (!(dev_get_flags(pDev) & IFF_PROMISC))
+ {
+ err = dev_change_flags(pDev, fIf | IFF_PROMISC);
+ if (!err)
+ Log(("vboxNetFlt: fixed IFF_PROMISC on %s (%d->%d)\n", pThis->szName, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
+ else
+ Log(("VBoxNetFlt: failed to fix IFF_PROMISC on %s, err=%d (%d->%d)\n",
+ pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
+ }
+#endif
+#if 0
+ }
+ else if (!err)
+ Log(("VBoxNetFlt: Waiting for the link to come up... (%d->%d)\n", cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
+ if (err)
+ LogRel(("VBoxNetFlt: Failed to put '%s' into promiscuous mode, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
+#endif
+ }
+ else
+ {
+ if (pThis->u.s.fPromiscuousSet)
+ {
+ rtnl_lock();
+ dev_set_promiscuity(pDev, -1);
+ rtnl_unlock();
+ Log(("vboxNetFltPortOsSetActive: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
+ }
+ pThis->u.s.fPromiscuousSet = false;
+
+ fIf = dev_get_flags(pDev);
+ Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
+ }
+
+ vboxNetFltLinuxReleaseNetDev(pThis, pDev);
+ }
+}
+
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ struct net_device *pDev;
+ bool fRegistered;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ pDev = (struct net_device *)ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pDev);
+ fRegistered = ASMAtomicUoReadBool(&pThis->u.s.fRegistered);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ if (fRegistered)
+ {
+ dev_remove_pack(&pThis->u.s.PacketType);
+ skb_queue_purge(&pThis->u.s.XmitQueue);
+ Log(("vboxNetFltOsDeleteInstance: this=%p: Packet handler removed, xmit queue purged.\n", pThis));
+ Log(("vboxNetFltOsDeleteInstance: Device %p(%s) released. ref=%d\n", pDev, pDev->name, atomic_read(&pDev->refcnt)));
+ dev_put(pDev);
+ }
+ Log(("vboxNetFltOsDeleteInstance: this=%p: Notifier removed.\n", pThis));
+ unregister_netdevice_notifier(&pThis->u.s.Notifier);
+}
+
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
+{
+ int err;
+ pThis->u.s.Notifier.notifier_call = vboxNetFltLinuxNotifierCallback;
+ err = register_netdevice_notifier(&pThis->u.s.Notifier);
+ if (err)
+ return VERR_INTNET_FLT_IF_FAILED;
+ if (!pThis->u.s.fRegistered)
+ {
+ unregister_netdevice_notifier(&pThis->u.s.Notifier);
+ LogRel(("VBoxNetFlt: failed to find %s.\n", pThis->szName));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+ }
+ Log(("vboxNetFltOsInitInstance: this=%p: Notifier installed.\n", pThis));
+ return pThis->fDisconnectedFromHost ? VERR_INTNET_FLT_IF_FAILED : VINF_SUCCESS;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ /*
+ * Init the linux specific members.
+ */
+ pThis->u.s.pDev = NULL;
+ pThis->u.s.fRegistered = false;
+ pThis->u.s.fPromiscuousSet = false;
+ memset(&pThis->u.s.PacketType, 0, sizeof(pThis->u.s.PacketType));
+ skb_queue_head_init(&pThis->u.s.XmitQueue);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&pThis->u.s.XmitTask, vboxNetFltLinuxXmitTask);
+#else
+ INIT_WORK(&pThis->u.s.XmitTask, vboxNetFltLinuxXmitTask, &pThis->u.s.XmitTask);
+#endif
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/dkms.conf b/src/VBox/HostDrivers/VBoxNetFlt/linux/dkms.conf
new file mode 100644
index 000000000..d20fef952
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/dkms.conf
@@ -0,0 +1,7 @@
+BUILT_MODULE_NAME=vboxnetflt
+DEST_MODULE_LOCATION=/kernel/misc
+PACKAGE_NAME=vboxnetflt
+PACKAGE_VERSION=_VERSION_
+AUTOINSTALL=yes
+CLEAN="make -C $dkms_tree/$module/$module_version/build clean"
+PRE_BUILD="do_Module.symvers vboxdrv restore $dkms_tree/$module/$module_version/build/Module.symvers"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/files_vboxnetflt b/src/VBox/HostDrivers/VBoxNetFlt/linux/files_vboxnetflt
new file mode 100644
index 000000000..95819176e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/files_vboxnetflt
@@ -0,0 +1,137 @@
+#!/bin/sh
+#
+# Shared file between Makefile.kmk and export_modules
+#
+# Copyright (C) 2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+## @todo
+# At the moment we'll be exporting everything we need here, later
+# we'll be linking against IPRT in vboxdrv like Darwin and Solaris does.
+
+VBOX_VBOXNETFLT_SOURCES=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/alloca.h=>include/iprt/alloca.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/intnet.h=>include/VBox/intnet.h \
+ ${PATH_ROOT}/include/VBox/stam.h=>include/VBox/stam.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c=>linux/VBoxNetFlt-linux.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c=>VBoxNetFlt.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h=>VBoxNetFltInternal.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIDC.h=>SUPDrvIDC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClient.c=>SUPR0IdcClient.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c=>SUPR0IdcClientComponent.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h=>SUPR0IdcClientInternal.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c=>SUPR0IdcClient-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/alloc/heapsimple.cpp=>alloc/heapsimple.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp=>common/err/RTErrConvertFromErrno.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp=>common/err/RTErrConvertToErrno.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/log.cpp=>common/log/log.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logellipsis.cpp=>common/log/logellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrel.cpp=>common/log/logrel.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrelellipsis.cpp=>common/log/logrelellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logcom.cpp=>common/log/logcom.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logformat.cpp=>common/log/logformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divdi3.c=>math/gcc/divdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/moddi3.c=>math/gcc/moddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/qdivrem.c=>math/gcc/qdivrem.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/quad.h=>math/gcc/quad.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformat.cpp=>common/string/strformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatrt.cpp=>common/string/strformatrt.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformattype.cpp=>common/string/strformattype.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf.cpp=>common/string/strprintf.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strtonum.cpp=>common/string/strtonum.c \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/initterm.h=>include/internal/initterm.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/magics.h=>include/internal/magics.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/memobj.h=>include/internal/memobj.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/string.h=>include/internal/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/thread.h=>include/internal/thread.h \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp=>generic/RTAssertShouldPanic-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp=>generic/RTLogWriteStdErr-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp=>generic/RTLogWriteStdOut-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp=>generic/RTLogWriteUser-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.cpp=>r0drv/alloc-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.h=>r0drv/alloc-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/initterm-r0drv.cpp=>r0drv/initterm-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mp-r0drv.h=>r0drv/mp-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mpnotification-r0drv.c=>r0drv/mpnotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/power-r0drv.h=>r0drv/power-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/powernotification-r0drv.c=>r0drv/powernotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c=>r0drv/linux/RTLogWriteDebugger-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c=>r0drv/linux/assert-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c=>r0drv/linux/alloc-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c=>r0drv/linux/initterm-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c=>r0drv/linux/memobj-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c=>r0drv/linux/mp-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c=>r0drv/linux/mpnotification-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c=>r0drv/linux/process-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c=>r0drv/linux/semevent-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c=>r0drv/linux/semeventmulti-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c=>r0drv/linux/semfastmutex-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c=>r0drv/linux/spinlock-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/string.h=>r0drv/linux/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c=>r0drv/linux/thread-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c=>r0drv/linux/thread2-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c=>r0drv/linux/time-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/memobj-r0drv.cpp=>r0drv/memobj-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/log-vbox.cpp=>VBox/log-vbox.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/strformat-vbox.cpp=>VBox/strformat-vbox.c \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+"
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c b/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c
new file mode 100644
index 000000000..f69fa8f60
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c
@@ -0,0 +1,3319 @@
+/* $Id: VBoxNetFlt-solaris.c 16082 2009-01-20 12:47:18Z vboxsync $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
+# define LOG_ENABLED
+#endif
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/cdefs.h>
+#include <VBox/version.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/alloca.h>
+#include <iprt/net.h>
+#include <iprt/mem.h>
+#include <iprt/thread.h>
+#include <iprt/spinlock.h>
+#include <iprt/crc32.h>
+
+#include <inet/ip.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/kstr.h>
+#include <sys/file.h>
+#include <sys/sockio.h>
+#include <sys/strsubr.h>
+#include <sys/pathname.h>
+#include <sys/t_kuser.h>
+
+#include <sys/types.h>
+#include <sys/dlpi.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ethernet.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/strsun.h>
+#include <sys/modctl.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunldi.h>
+
+/*
+ * Experimental: Using netinfo interfaces and queuing out packets.
+ * This is for playing better with IPFilter.
+ */
+#undef VBOXNETFLT_SOLARIS_USE_NETINFO
+#ifdef VBOXNETFLT_SOLARIS_USE_NETINFO
+# include <sys/neti.h>
+#endif
+
+// Workaround for very strange define in sys/user.h
+// #define u (curproc->p_user) /* user is now part of proc structure */
+#ifdef u
+#undef u
+#endif
+
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "../VBoxNetFltInternal.h"
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define VBOXSOLQUOTE2(x) #x
+#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
+/** The module name. */
+#define DEVICE_NAME "vboxflt"
+/** The module descriptions as seen in 'modinfo'. */
+#define DEVICE_DESC_DRV "VirtualBox NetDrv"
+#define DEVICE_DESC_MOD "VirtualBox NetMod"
+
+/** @todo Remove the below hackery once done! */
+#if defined(DEBUG_ramshankar) && defined(LOG_ENABLED)
+# undef Log
+# define Log LogRel
+# undef LogFlow
+# define LogFlow LogRel
+#endif
+
+/** Maximum loopback packet queue size per interface */
+#define VBOXNETFLT_LOOPBACK_SIZE 32
+
+/*******************************************************************************
+* Global Functions *
+*******************************************************************************/
+/**
+ * Stream Driver hooks.
+ */
+static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
+static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
+static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
+
+/**
+ * Stream Module hooks.
+ */
+static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fFile, int fStream, cred_t *pCred);
+static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fFile, cred_t *pCred);
+static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg);
+static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg);
+
+/**
+ * OS specific hooks invoked from common VBoxNetFlt ring-0.
+ */
+bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis);
+void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac);
+bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac);
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive);
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis);
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis);
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis);
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis);
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis);
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Streams: module info.
+ */
+static struct module_info g_VBoxNetFltSolarisModInfo =
+{
+ 0xbad, /* module id */
+ DEVICE_NAME,
+ 0, /* min. packet size */
+ INFPSZ, /* max. packet size */
+ 0, /* hi-water mask */
+ 0 /* lo-water mask */
+};
+
+/**
+ * Streams: read queue hooks.
+ */
+static struct qinit g_VBoxNetFltSolarisReadQ =
+{
+ VBoxNetFltSolarisModReadPut,
+ NULL, /* service */
+ VBoxNetFltSolarisModOpen,
+ VBoxNetFltSolarisModClose,
+ NULL, /* admin (reserved) */
+ &g_VBoxNetFltSolarisModInfo,
+ NULL /* module stats */
+};
+
+/**
+ * Streams: write queue hooks.
+ */
+static struct qinit g_VBoxNetFltSolarisWriteQ =
+{
+ VBoxNetFltSolarisModWritePut,
+ NULL, /* service */
+ NULL, /* open */
+ NULL, /* close */
+ NULL, /* admin (reserved) */
+ &g_VBoxNetFltSolarisModInfo,
+ NULL /* module stats */
+};
+
+/**
+ * Streams: IO stream tab.
+ */
+static struct streamtab g_VBoxNetFltSolarisStreamTab =
+{
+ &g_VBoxNetFltSolarisReadQ,
+ &g_VBoxNetFltSolarisWriteQ,
+ NULL, /* muxread init */
+ NULL /* muxwrite init */
+};
+
+/**
+ * cb_ops: driver char/block entry points
+ */
+static struct cb_ops g_VBoxNetFltSolarisCbOps =
+{
+ nulldev, /* cb open */
+ nulldev, /* cb close */
+ nodev, /* b strategy */
+ nodev, /* b dump */
+ nodev, /* b print */
+ nodev, /* cb read */
+ nodev, /* cb write */
+ nodev, /* cb ioctl */
+ nodev, /* c devmap */
+ nodev, /* c mmap */
+ nodev, /* c segmap */
+ nochpoll, /* c poll */
+ ddi_prop_op, /* property ops */
+ &g_VBoxNetFltSolarisStreamTab,
+ D_NEW | D_MP | D_MTQPAIR, /* compat. flag */
+ CB_REV /* revision */
+};
+
+/**
+ * dev_ops: driver entry/exit and other ops.
+ */
+static struct dev_ops g_VBoxNetFltSolarisDevOps =
+{
+ DEVO_REV, /* driver build revision */
+ 0, /* ref count */
+ VBoxNetFltSolarisGetInfo,
+ nulldev, /* identify */
+ nulldev, /* probe */
+ VBoxNetFltSolarisAttach,
+ VBoxNetFltSolarisDetach,
+ nodev, /* reset */
+ &g_VBoxNetFltSolarisCbOps,
+ (struct bus_ops *)0,
+ nodev /* power */
+};
+
+/**
+ * modldrv: export driver specifics to kernel
+ */
+static struct modldrv g_VBoxNetFltSolarisDriver =
+{
+ &mod_driverops, /* extern from kernel */
+ DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
+ &g_VBoxNetFltSolarisDevOps
+};
+
+/**
+ * fmodsw: streams module ops
+ */
+static struct fmodsw g_VBoxNetFltSolarisModOps =
+{
+ DEVICE_NAME,
+ &g_VBoxNetFltSolarisStreamTab,
+ D_NEW | D_MP | D_MTQPAIR
+};
+
+/**
+ * modlstrmod: streams module specifics to kernel
+ */
+static struct modlstrmod g_VBoxNetFltSolarisModule =
+{
+ &mod_strmodops, /* extern from kernel */
+ DEVICE_DESC_MOD " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
+ &g_VBoxNetFltSolarisModOps
+};
+
+/**
+ * modlinkage: export install/remove/info to the kernel
+ */
+static struct modlinkage g_VBoxNetFltSolarisModLinkage =
+{
+ MODREV_1, /* loadable module system revision */
+ &g_VBoxNetFltSolarisDriver, /* streams driver framework */
+ &g_VBoxNetFltSolarisModule, /* streams module framework */
+ NULL /* terminate array of linkage structures */
+};
+
+struct vboxnetflt_state_t;
+
+/**
+ * vboxnetflt_dladdr_t: DL SAP address format
+ */
+typedef struct vboxnetflt_dladdr_t
+{
+ ether_addr_t Mac;
+ uint16_t SAP;
+} vboxnetflt_dladdr_t;
+
+#define VBOXNETFLT_DLADDRL sizeof(vboxnetflt_dladdr_t)
+
+/**
+ * which stream is this?
+ */
+typedef enum VBOXNETFLTSTREAMTYPE
+{
+ kUndefined = 0,
+ kIp4Stream = 0x1b,
+ kIp6Stream = 0xcc,
+ kArpStream = 0xab,
+ kPromiscStream = 0xdf
+} VBOXNETFLTSTREAMTYPE;
+
+/**
+ * loopback packet identifier
+ */
+typedef struct VBOXNETFLTPACKETID
+{
+ struct VBOXNETFLTPACKETID *pNext;
+ uint16_t cbPacket;
+ uint16_t Checksum;
+ RTMAC SrcMac;
+ RTMAC DstMac;
+} VBOXNETFLTPACKETID;
+typedef struct VBOXNETFLTPACKETID *PVBOXNETFLTPACKETID;
+
+/**
+ * vboxnetflt_stream_t: per-stream data (multiple streams per interface)
+ */
+typedef struct vboxnetflt_stream_t
+{
+ int DevMinor; /* minor device no. (for clone) */
+ queue_t *pReadQueue; /* read side queue */
+ struct vboxnetflt_stream_t *pNext; /* next stream in list */
+ PVBOXNETFLTINS volatile pThis; /* the backend instance */
+ VBOXNETFLTSTREAMTYPE Type; /* the type of the stream */
+} vboxnetflt_stream_t;
+
+/**
+ * vboxnetflt_promisc_stream_t: per-interface dedicated stream data
+ */
+typedef struct vboxnetflt_promisc_stream_t
+{
+ vboxnetflt_stream_t Stream; /* The generic stream */
+ bool fPromisc; /* cached promiscous value */
+ bool fRawMode; /* whether raw mode request was successful */
+ uint32_t ModeReqId; /* track MIOCTLs for swallowing our fake request acknowledgements */
+ size_t cLoopback; /* loopback queue size list */
+ PVBOXNETFLTPACKETID pHead; /* loopback packet identifier head */
+ PVBOXNETFLTPACKETID pTail; /* loopback packet identifier tail */
+} vboxnetflt_promisc_stream_t;
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+static int vboxNetFltSolarisSetRawMode(vboxnetflt_promisc_stream_t *pPromiscStream);
+/* static int vboxNetFltSolarisSetFastMode(queue_t *pQueue); */
+
+static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue);
+static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pPhysAddrAckMsg);
+static int vboxNetFltSolarisBindReq(queue_t *pQueue, int SAP);
+static int vboxNetFltSolarisNotifyReq(queue_t *pQueue);
+
+static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg);
+static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg);
+
+static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg);
+static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
+static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg);
+
+static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
+static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
+static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
+static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg);
+static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg);
+static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** Global device info handle. */
+static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
+
+/** The (common) global data. */
+static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
+
+/** The list of all opened streams. */
+vboxnetflt_stream_t *g_VBoxNetFltSolarisStreams;
+
+/** Global mutex protecting open/close. */
+static RTSEMFASTMUTEX g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
+
+/**
+ * g_VBoxNetFltInstance is the current PVBOXNETFLTINS to be associated with the stream being created
+ * in ModOpen. This is just shared global data between the dynamic attach and the ModOpen procedure.
+ */
+PVBOXNETFLTINS volatile g_VBoxNetFltSolarisInstance;
+
+/** Goes along with the instance to determine type of stream being opened/created. */
+VBOXNETFLTSTREAMTYPE volatile g_VBoxNetFltSolarisStreamType;
+
+/** GCC C++ hack. */
+unsigned __gxx_personality_v0 = 0xdecea5ed;
+
+
+/**
+ * Kernel entry points
+ */
+int _init(void)
+{
+ LogFlow((DEVICE_NAME ":_init\n"));
+
+ /*
+ * Prevent module autounloading.
+ */
+ modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
+ if (pModCtl)
+ pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
+ else
+ LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
+
+ /*
+ * Initialize IPRT.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize Solaris specific globals here.
+ */
+ g_VBoxNetFltSolarisStreams = NULL;
+ g_VBoxNetFltSolarisInstance = NULL;
+
+ int rc = RTSemFastMutexCreate(&g_VBoxNetFltSolarisMtx);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the globals and connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltSolarisGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
+ if (!rc)
+ return rc;
+
+ LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
+ vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
+ }
+ else
+ LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
+
+ RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
+ g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
+ }
+
+ RTR0Term();
+ }
+ else
+ LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
+
+ memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
+ return -1;
+}
+
+
+int _fini(void)
+{
+ int rc;
+ LogFlow((DEVICE_NAME ":_fini\n"));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ rc = vboxNetFltTryDeleteGlobals(&g_VBoxNetFltSolarisGlobals);
+ if (RT_FAILURE(rc))
+ {
+ LogRel((DEVICE_NAME ":_fini - busy!\n"));
+ return EBUSY;
+ }
+
+ if (g_VBoxNetFltSolarisMtx != NIL_RTSEMFASTMUTEX)
+ {
+ RTSemFastMutexDestroy(g_VBoxNetFltSolarisMtx);
+ g_VBoxNetFltSolarisMtx = NIL_RTSEMFASTMUTEX;
+ }
+
+ RTR0Term();
+
+ return mod_remove(&g_VBoxNetFltSolarisModLinkage);
+}
+
+
+int _info(struct modinfo *pModInfo)
+{
+ LogFlow((DEVICE_NAME ":_info\n"));
+
+ int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
+
+ LogFlow((DEVICE_NAME ":_info returns %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * Attach entry point, to attach a device to the system or resume it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (attach/resume).
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
+{
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ switch (enmCmd)
+ {
+ case DDI_ATTACH:
+ {
+ int instance = ddi_get_instance(pDip);
+ int rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, CLONE_DEV);
+ if (rc == DDI_SUCCESS)
+ {
+ g_pVBoxNetFltSolarisDip = pDip;
+ ddi_report_dev(pDip);
+ return DDI_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisAttach failed to create minor node. rc%d\n", rc));
+ return DDI_FAILURE;
+ }
+
+ case DDI_RESUME:
+ {
+ /* Nothing to do here... */
+ return DDI_SUCCESS;
+ }
+ }
+ return DDI_FAILURE;
+}
+
+
+/**
+ * Detach entry point, to detach a device to the system or suspend it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (detach/suspend).
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
+{
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ switch (enmCmd)
+ {
+ case DDI_DETACH:
+ {
+ int instance = ddi_get_instance(pDip);
+ ddi_remove_minor_node(pDip, NULL);
+ return DDI_SUCCESS;
+ }
+
+ case DDI_RESUME:
+ {
+ /* Nothing to do here... */
+ return DDI_SUCCESS;
+ }
+ }
+ return DDI_FAILURE;
+}
+
+
+/**
+ * Info entry point, called by solaris kernel for obtaining driver info.
+ *
+ * @param pDip The module structure instance (do not use).
+ * @param enmCmd Information request type.
+ * @param pvArg Type specific argument.
+ * @param ppvResult Where to store the requested info.
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppResult)
+{
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd,
+ getminor((dev_t)pvArg)));
+
+ switch (enmCmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ {
+ *ppResult = g_pVBoxNetFltSolarisDip;
+ return DDI_SUCCESS;
+ }
+
+ case DDI_INFO_DEVT2INSTANCE:
+ {
+ int instance = getminor((dev_t)pvArg);
+ *ppResult = (void *)(uintptr_t)instance;
+ return DDI_SUCCESS;
+ }
+ }
+
+ return DDI_FAILURE;
+}
+
+
+/**
+ * Stream module open entry point, initializes the queue and allows streams processing.
+ *
+ * @param pQueue Pointer to the read queue (cannot be NULL).
+ * @param pDev Pointer to the dev_t associated with the driver at the end of the stream.
+ * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
+ * @param fStreamMode Stream open mode.
+ * @param pCred Pointer to user credentials.
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisModOpen(queue_t *pQueue, dev_t *pDev, int fOpenMode, int fStreamMode, cred_t *pCred)
+{
+ Assert(pQueue);
+
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen pQueue=%p pDev=%p fOpenMode=%d fStreamMode=%d\n", pQueue, pDev,
+ fOpenMode, fStreamMode));
+
+ int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Already open?
+ */
+ if (pQueue->q_ptr)
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen invalid open.\n"));
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENOENT;
+ }
+
+ /*
+ * Check for the VirtualBox instance.
+ */
+ PVBOXNETFLTINS pThis = g_VBoxNetFltSolarisInstance;
+ if (!pThis)
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to get VirtualBox instance.\n"));
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENOENT;
+ }
+
+ /*
+ * Check VirtualBox stream type.
+ */
+ if (g_VBoxNetFltSolarisStreamType == kUndefined)
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed due to undefined VirtualBox open mode.\n"));
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENOENT;
+ }
+
+ /*
+ * Get minor number. For clone opens provide a new dev_t.
+ */
+ minor_t DevMinor = 0;
+ vboxnetflt_stream_t *pStream = NULL;
+ vboxnetflt_stream_t **ppPrevStream = &g_VBoxNetFltSolarisStreams;
+ if (fStreamMode == CLONEOPEN)
+ {
+ for (; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
+ {
+ if (DevMinor < pStream->DevMinor)
+ break;
+ DevMinor++;
+ }
+ *pDev = makedevice(getmajor(*pDev), DevMinor);
+ }
+ else
+ DevMinor = getminor(*pDev);
+
+ if (g_VBoxNetFltSolarisStreamType == kPromiscStream)
+ {
+ vboxnetflt_promisc_stream_t *pPromiscStream = RTMemAlloc(sizeof(vboxnetflt_promisc_stream_t));
+ if (RT_UNLIKELY(!pPromiscStream))
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate promiscuous stream data.\n"));
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENOMEM;
+ }
+
+ pPromiscStream->fPromisc = false;
+ pPromiscStream->fRawMode = false;
+ pPromiscStream->ModeReqId = 0;
+ pPromiscStream->pHead = NULL;
+ pPromiscStream->pTail = NULL;
+ pPromiscStream->cLoopback = 0;
+ pStream = (vboxnetflt_stream_t *)pPromiscStream;
+ }
+ else
+ {
+ /*
+ * Allocate & initialize per-stream data. Hook it into the (read and write) queue's module specific data.
+ */
+ pStream = RTMemAlloc(sizeof(vboxnetflt_stream_t));
+ if (RT_UNLIKELY(!pStream))
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModOpen failed to allocate stream data.\n"));
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENOMEM;
+ }
+ }
+ pStream->DevMinor = DevMinor;
+ pStream->pReadQueue = pQueue;
+
+ /*
+ * Pick up the current global VBOXNETFLTINS instance as
+ * the one that we will associate this stream with.
+ */
+ ASMAtomicUoWritePtr((void * volatile *)&pStream->pThis, pThis);
+ pStream->Type = g_VBoxNetFltSolarisStreamType;
+ switch (pStream->Type)
+ {
+ case kIp4Stream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvIp4Stream, pStream); break;
+ case kIp6Stream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvIp6Stream, pStream); break;
+ case kArpStream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvArpStream, pStream); break;
+ case kPromiscStream: ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.pvPromiscStream, pStream); break;
+ default: /* Heh. */
+ {
+ AssertRelease(pStream->Type);
+ break;
+ }
+ }
+
+ pQueue->q_ptr = pStream;
+ WR(pQueue)->q_ptr = pStream;
+
+ /*
+ * Link it to the list of streams.
+ */
+ pStream->pNext = *ppPrevStream;
+ *ppPrevStream = pStream;
+
+ /*
+ * Release global lock, & do not hold locks across putnext calls.
+ */
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+
+ qprocson(pQueue);
+
+ /*
+ * Don't hold the spinlocks across putnext calls as it could
+ * (and does mostly) re-enter the put procedure on the same thread.
+ */
+ if (pStream->Type == kPromiscStream)
+ {
+ vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
+
+ /*
+ * Bind to SAP 0 (DL_ETHER).
+ * Note: We don't support DL_TPR (token passing ring) SAP as that is unnecessary asynchronous
+ * work to get DL_INFO_REQ acknowledgements and determine SAP based on the Mac Type etc.
+ * Besides TPR doesn't really exist anymore practically as far as I know.
+ */
+ int rc = vboxNetFltSolarisBindReq(pStream->pReadQueue, 0 /* SAP */);
+ if (RT_LIKELY(RT_SUCCESS(rc)))
+ {
+ /*
+ * Request the physical address (we cache the acknowledgement).
+ */
+ rc = vboxNetFltSolarisPhysAddrReq(pStream->pReadQueue);
+ if (RT_LIKELY(RT_SUCCESS(rc)))
+ {
+ /*
+ * Ask for DLPI link notifications, don't bother check for errors here.
+ */
+ vboxNetFltSolarisNotifyReq(pStream->pReadQueue);
+
+ /*
+ * Enable raw mode.
+ */
+ rc = vboxNetFltSolarisSetRawMode(pPromiscStream);
+ if (RT_FAILURE(rc))
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Rrc.\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisSetRawMode failed rc=%Rrc.\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisBindReq failed rc=%Rrc.\n", rc));
+ }
+
+ NOREF(fOpenMode);
+ NOREF(pCred);
+
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModOpen returns 0, DevMinor=%d pQueue=%p\n", DevMinor, pStream->pReadQueue));
+
+ return 0;
+}
+
+
+/**
+ * Stream module close entry point, undoes the work done on open and closes the stream.
+ *
+ * @param pQueue Pointer to the read queue (cannot be NULL).
+ * @param fOpenMode Open mode (always 0 for streams driver, thus ignored).
+ * @param pCred Pointer to user credentials.
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisModClose(queue_t *pQueue, int fOpenMode, cred_t *pCred)
+{
+ Assert(pQueue);
+
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModClose pQueue=%p fOpenMode=%d\n", pQueue, fOpenMode));
+
+ int rc = RTSemFastMutexRequest(g_VBoxNetFltSolarisMtx);
+ AssertRCReturn(rc, rc);
+
+ vboxnetflt_stream_t *pStream = NULL;
+ vboxnetflt_stream_t **ppPrevStream = NULL;
+
+ /*
+ * Get instance data.
+ */
+ pStream = (vboxnetflt_stream_t *)pQueue->q_ptr;
+ if (RT_UNLIKELY(!pStream))
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModClose failed to get stream.\n"));
+ vboxNetFltRelease(pStream->pThis, false /* fBusy */);
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+ return ENXIO;
+ }
+
+ if (pStream->Type == kPromiscStream)
+ {
+ flushq(pQueue, FLUSHALL);
+ flushq(WR(pQueue), FLUSHALL);
+ }
+
+ qprocsoff(pQueue);
+
+ if (pStream->Type == kPromiscStream)
+ {
+ vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
+
+ int rc = RTSemFastMutexRequest(pStream->pThis->u.s.hFastMtx);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Free-up loopback buffers.
+ */
+ PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
+ while (pCur)
+ {
+ PVBOXNETFLTPACKETID pNext = pCur->pNext;
+ RTMemFree(pCur);
+ pCur = pNext;
+ }
+ pPromiscStream->pHead = NULL;
+ pPromiscStream->pTail = NULL;
+ pPromiscStream->cLoopback = 0;
+
+ RTSemFastMutexRelease(pStream->pThis->u.s.hFastMtx);
+ }
+
+ /*
+ * Unlink it from the list of streams.
+ */
+ for (ppPrevStream = &g_VBoxNetFltSolarisStreams; (pStream = *ppPrevStream) != NULL; ppPrevStream = &pStream->pNext)
+ if (pStream == (vboxnetflt_stream_t *)pQueue->q_ptr)
+ break;
+ *ppPrevStream = pStream->pNext;
+
+ /*
+ * Delete the stream.
+ */
+ switch (pStream->Type)
+ {
+ case kIp4Stream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvIp4Stream, NULL); break;
+ case kIp6Stream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvIp6Stream, NULL); break;
+ case kArpStream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvArpStream, NULL); break;
+ case kPromiscStream: ASMAtomicUoWritePtr(pStream->pThis->u.s.pvPromiscStream, NULL); break;
+ default: /* Heh. */
+ {
+ AssertRelease(pStream->Type);
+ break;
+ }
+ }
+
+ vboxNetFltRelease(pStream->pThis, false /* fBusy */);
+ RTMemFree(pStream);
+ pQueue->q_ptr = NULL;
+ WR(pQueue)->q_ptr = NULL;
+
+ NOREF(fOpenMode);
+ NOREF(pCred);
+
+ RTSemFastMutexRelease(g_VBoxNetFltSolarisMtx);
+
+ return 0;
+}
+
+
+/**
+ * Read side put procedure for processing messages in the read queue.
+ * All streams, bound and unbound share this read procedure.
+ *
+ * @param pQueue Pointer to the read queue.
+ * @param pMsg Pointer to the message.
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisModReadPut(queue_t *pQueue, mblk_t *pMsg)
+{
+ if (!pMsg)
+ return 0;
+
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut pQueue=%p pMsg=%p\n", pQueue, pMsg));
+
+ bool fSendUpstream = true;
+ vboxnetflt_stream_t *pStream = pQueue->q_ptr;
+ PVBOXNETFLTINS pThis = NULL;
+
+ /*
+ * In the unlikely case where VirtualBox crashed and this filter
+ * is somehow still in the host stream we must try not to panic the host.
+ */
+ if ( pStream
+ && pStream->Type == kPromiscStream)
+ {
+ fSendUpstream = false;
+ pThis = ASMAtomicUoReadPtr((void * volatile *)&pStream->pThis);
+ if (RT_LIKELY(pThis))
+ {
+ /*
+ * Retain the instance if we're filtering regardless of we are active or not
+ * The reason being even when we are inactive we reference the instance (e.g
+ * the promiscuous OFF acknowledgement case).
+ */
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ const bool fActive = ASMAtomicUoReadBool(&pThis->fActive);
+ vboxNetFltRetain(pThis, true /* fBusy */);
+ RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+ vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
+
+ switch (DB_TYPE(pMsg))
+ {
+ case M_DATA:
+ {
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut M_DATA\n"));
+
+ if ( fActive
+ && pPromiscStream->fRawMode)
+ {
+ vboxNetFltSolarisRecv(pThis, pStream, pQueue, pMsg);
+ }
+ break;
+ }
+
+ case M_PROTO:
+ case M_PCPROTO:
+ {
+ union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
+ t_uscalar_t Prim = pPrim->dl_primitive;
+
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO %d\n", Prim));
+ switch (Prim)
+ {
+ case DL_NOTIFY_IND:
+ {
+ if (MBLKL(pMsg) < DL_NOTIFY_IND_SIZE)
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Invalid notification size; expected>=%d got=%d\n",
+ DL_NOTIFY_IND_SIZE, MBLKL(pMsg)));
+ break;
+ }
+
+ dl_notify_ind_t *pNotifyInd = (dl_notify_ind_t *)pMsg->b_rptr;
+ switch (pNotifyInd->dl_notification)
+ {
+ case DL_NOTE_PHYS_ADDR:
+ {
+ if (pNotifyInd->dl_data != DL_CURR_PHYS_ADDR)
+ break;
+
+ size_t cOffset = pNotifyInd->dl_addr_offset;
+ size_t cbAddr = pNotifyInd->dl_addr_length;
+
+ if (!cOffset || !cbAddr)
+ {
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR. Invalid offset/addr.\n"));
+ fSendUpstream = false;
+ break;
+ }
+
+ bcopy(pMsg->b_rptr + cOffset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_PHYS_ADDR. New Mac=%.*Rhxs\n",
+ sizeof(pThis->u.s.Mac), &pThis->u.s.Mac));
+ break;
+ }
+
+ case DL_NOTE_LINK_UP:
+ {
+ const bool fDisconnected = ASMAtomicUoReadBool(&pThis->fActive);
+ if (fDisconnected)
+ {
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_UP.\n"));
+ }
+ break;
+ }
+
+ case DL_NOTE_LINK_DOWN:
+ {
+ const bool fDisconnected = ASMAtomicUoReadBool(&pThis->fActive);
+ if (!fDisconnected)
+ {
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_NOTE_LINK_DOWN.\n"));
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ case DL_BIND_ACK:
+ {
+ /*
+ * Swallow our bind request acknowledgement.
+ */
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: DL_BIND_ACK. Bound to requested SAP!\n"));
+ break;
+ }
+
+ case DL_PHYS_ADDR_ACK:
+ {
+ /*
+ * Swallow our physical address request acknowledgement.
+ */
+ vboxNetFltSolarisCachePhysAddr(pThis, pMsg);
+ break;
+ }
+
+ case DL_OK_ACK:
+ {
+ /*
+ * Swallow our fake promiscous request acknowledgement.
+ */
+ dl_ok_ack_t *pOkAck = (dl_ok_ack_t *)pMsg->b_rptr;
+ if (pOkAck->dl_correct_primitive == DL_PROMISCON_REQ)
+ {
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is ON.\n"));
+ pPromiscStream->fPromisc = true;
+ }
+ else if (pOkAck->dl_correct_primitive == DL_PROMISCOFF_REQ)
+ {
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_PCPROTO: DL_OK_ACK: fPromisc is OFF.\n"));
+ pPromiscStream->fPromisc = false;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ case M_IOCACK:
+ {
+ /*
+ * Swallow our fake raw/fast path mode request acknowledgement.
+ */
+ struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
+ if (pIOC->ioc_id == pPromiscStream->ModeReqId)
+ {
+ pPromiscStream->fRawMode = true;
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Mode acknowledgement. RawMode is %s\n",
+ pPromiscStream->fRawMode ? "ON" : "OFF"));
+ }
+ break;
+ }
+
+ case M_IOCNAK:
+ {
+ /*
+ * Swallow our fake raw/fast path mode request not acknowledged.
+ */
+ struct iocblk *pIOC = (struct iocblk *)pMsg->b_rptr;
+ if (pIOC->ioc_id == pPromiscStream->ModeReqId)
+ {
+ pPromiscStream->fRawMode = false;
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: WARNING! Mode not acknowledged. RawMode is %s\n",
+ pPromiscStream->fRawMode ? "ON" : "OFF"));
+ }
+ break;
+ }
+
+ case M_FLUSH:
+ {
+ /*
+ * We must support flushing queues.
+ */
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: M_FLUSH\n"));
+ if (*pMsg->b_rptr & FLUSHR)
+ flushq(pQueue, FLUSHALL);
+ break;
+ }
+ }
+
+ vboxNetFltRelease(pThis, true /* fBusy */);
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetFltSolarisModReadPut: Could not find VirtualBox instance!!\n"));
+ }
+
+ if (fSendUpstream)
+ {
+ /*
+ * Don't queue up things here, can cause bad things to happen when the system
+ * is under heavy loads and we need to jam across high priority messages which
+ * if it's not done properly will end up in an infinite loop.
+ */
+ putnext(pQueue, pMsg);
+ }
+ else
+ {
+ /*
+ * We need to free up the message if we don't pass it through.
+ */
+ freemsg(pMsg);
+ }
+
+ return 0;
+}
+
+
+/**
+ * Write side put procedure for processing messages in the write queue.
+ * All streams, bound and unbound share this write procedure.
+ *
+ * @param pQueue Pointer to the write queue.
+ * @param pMsg Pointer to the message.
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetFltSolarisModWritePut(queue_t *pQueue, mblk_t *pMsg)
+{
+ LogFlow((DEVICE_NAME ":VBoxNetFltSolarisModWritePut pQueue=%p pMsg=%p\n", pQueue, pMsg));
+
+ putnext(pQueue, pMsg);
+ return 0;
+}
+
+
+/**
+ * Put the stream in raw mode.
+ *
+ * @returns VBox status code.
+ * @param pQueue Pointer to the read queue.
+ */
+static int vboxNetFltSolarisSetRawMode(vboxnetflt_promisc_stream_t *pPromiscStream)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetRawMode pPromiscStream=%p\n", pPromiscStream));
+
+ mblk_t *pRawMsg = NULL;
+ pRawMsg = mkiocb(DLIOCRAW);
+ if (RT_UNLIKELY(!pRawMsg))
+ return VERR_NO_MEMORY;
+
+ queue_t *pQueue = pPromiscStream->Stream.pReadQueue;
+ if (!pQueue)
+ return VERR_INVALID_POINTER;
+
+ struct iocblk *pIOC = (struct iocblk *)pRawMsg->b_rptr;
+ pPromiscStream->ModeReqId = pIOC->ioc_id;
+ pIOC->ioc_count = 0;
+
+ qreply(pQueue, pRawMsg);
+ return VINF_SUCCESS;
+}
+
+
+#if 0
+/**
+ * Put the stream back in fast path mode.
+ *
+ * @returns VBox status code.
+ * @param pQueue Pointer to the read queue.
+ */
+static int vboxNetFltSolarisSetFastMode(queue_t *pQueue)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisSetFastMode pQueue=%p\n", pQueue));
+
+ mblk_t *pFastMsg = mkiocb(DL_IOC_HDR_INFO);
+ if (RT_UNLIKELY(!pFastMsg))
+ return VERR_NO_MEMORY;
+
+ vboxnetflt_stream_t *pStream = pQueue->q_ptr;
+ struct iocblk *pIOC = (struct iocblk *)pFastMsg->b_rptr;
+ pStream->ModeReqId = pIOC->ioc_id;
+
+ size_t cbReq = sizeof(dl_unitdata_req_t) + sizeof(vboxnetflt_dladdr_t);
+ mblk_t *pDataReqMsg = allocb(cbReq, BPRI_MED);
+ if (RT_UNLIKELY(!pDataReqMsg))
+ return VERR_NO_MEMORY;
+
+ DB_TYPE(pDataReqMsg) = M_PROTO;
+ dl_unitdata_req_t *pDataReq = (dl_unitdata_req_t *)pDataReqMsg->b_rptr;
+ pDataReq->dl_primitive = DL_UNITDATA_REQ;
+ pDataReq->dl_dest_addr_length = sizeof(vboxnetflt_dladdr_t);
+ pDataReq->dl_dest_addr_offset = sizeof(dl_unitdata_req_t);
+ pDataReq->dl_priority.dl_min = 0;
+ pDataReq->dl_priority.dl_max = 0;
+
+ bzero(pDataReqMsg->b_rptr + sizeof(dl_unitdata_req_t), sizeof(vboxnetflt_dladdr_t));
+ pDataReqMsg->b_wptr = pDataReqMsg->b_rptr + cbReq;
+
+ /*
+ * Link the data format request message into the header ioctl message.
+ */
+ pFastMsg->b_cont = pDataReqMsg;
+ pIOC->ioc_count = msgdsize(pDataReqMsg);
+
+ qreply(pQueue, pFastMsg);
+ return VINF_SUCCESS;
+}
+#endif
+
+
+/**
+ * Send fake promiscous mode requests downstream.
+ *
+ * @param pQueue Pointer to the read queue.
+ * @param fPromisc Whether to enable promiscous mode or not.
+ * @param PromiscLevel Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
+ *
+ * @returns VBox error code.
+ */
+static int vboxNetFltSolarisPromiscReq(queue_t *pQueue, bool fPromisc)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisPromiscReq pQueue=%p fPromisc=%d\n", pQueue, fPromisc));
+
+ t_uscalar_t Cmd;
+ size_t cbReq = 0;
+ if (fPromisc)
+ {
+ Cmd = DL_PROMISCON_REQ;
+ cbReq = DL_PROMISCON_REQ_SIZE;
+ }
+ else
+ {
+ Cmd = DL_PROMISCOFF_REQ;
+ cbReq = DL_PROMISCOFF_REQ_SIZE;
+ }
+
+ mblk_t *pPromiscPhysMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
+ if (RT_UNLIKELY(!pPromiscPhysMsg))
+ return VERR_NO_MEMORY;
+
+ mblk_t *pPromiscSapMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
+ if (RT_UNLIKELY(!pPromiscSapMsg))
+ {
+ freemsg(pPromiscPhysMsg);
+ return VERR_NO_MEMORY;
+ }
+
+ if (fPromisc)
+ {
+ ((dl_promiscon_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
+ ((dl_promiscon_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
+ }
+ else
+ {
+ ((dl_promiscoff_req_t *)pPromiscPhysMsg->b_rptr)->dl_level = DL_PROMISC_PHYS;
+ ((dl_promiscoff_req_t *)pPromiscSapMsg->b_rptr)->dl_level = DL_PROMISC_SAP;
+ }
+
+ qreply(pQueue, pPromiscPhysMsg);
+ qreply(pQueue, pPromiscSapMsg);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Send a fake physical address request downstream.
+ *
+ * @returns VBox status code.
+ * @param pQueue Pointer to the read queue.
+ * @param pMsg Pointer to the request message.
+ */
+static int vboxNetFltSolarisPhysAddrReq(queue_t *pQueue)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisPhysAddrReq pQueue=%p\n", pQueue));
+
+ t_uscalar_t Cmd = DL_PHYS_ADDR_REQ;
+ size_t cbReq = DL_PHYS_ADDR_REQ_SIZE;
+ mblk_t *pPhysAddrMsg = mexchange(NULL, NULL, cbReq, M_PROTO, Cmd);
+ if (RT_UNLIKELY(!pPhysAddrMsg))
+ return VERR_NO_MEMORY;
+
+ dl_phys_addr_req_t *pPhysAddrReq = (dl_phys_addr_req_t *)pPhysAddrMsg->b_rptr;
+ pPhysAddrReq->dl_addr_type = DL_CURR_PHYS_ADDR;
+
+ qreply(pQueue, pPhysAddrMsg);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Cache the MAC address into the VirtualBox instance given a physical
+ * address acknowledgement message.
+ *
+ * @param pThis The instance.
+ * @param pMsg Pointer to the physical address acknowledgement message.
+ */
+static void vboxNetFltSolarisCachePhysAddr(PVBOXNETFLTINS pThis, mblk_t *pMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr pThis=%p pMsg=%p\n", pThis, pMsg));
+
+ AssertCompile(sizeof(RTMAC) == ETHERADDRL);
+ dl_phys_addr_ack_t *pPhysAddrAck = (dl_phys_addr_ack_t *)pMsg->b_rptr;
+ if (pPhysAddrAck->dl_addr_length == sizeof(pThis->u.s.Mac))
+ {
+ bcopy(pMsg->b_rptr + pPhysAddrAck->dl_addr_offset, &pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: DL_PHYS_ADDR_ACK: Mac=%.*Rhxs\n", sizeof(pThis->u.s.Mac),
+ &pThis->u.s.Mac));
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisCachePhysAddr: Invalid address size. expected=%d got=%d\n", ETHERADDRL,
+ pPhysAddrAck->dl_addr_length));
+ }
+}
+
+
+/**
+ * Prepare DLPI bind request to a SAP.
+ *
+ * @returns VBox status code.
+ * @param pQueue Pointer to the read queue.
+ * @param SAP The SAP to bind the stream to.
+ */
+static int vboxNetFltSolarisBindReq(queue_t *pQueue, int SAP)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisBindReq SAP=%d\n", SAP));
+
+ mblk_t *pBindMsg = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
+ if (RT_UNLIKELY(!pBindMsg))
+ return VERR_NO_MEMORY;
+
+ dl_bind_req_t *pBindReq = (dl_bind_req_t *)pBindMsg->b_rptr;
+ pBindReq->dl_sap = SAP;
+ pBindReq->dl_max_conind = 0;
+ pBindReq->dl_conn_mgmt = 0;
+ pBindReq->dl_xidtest_flg = 0;
+ pBindReq->dl_service_mode = DL_CLDLS;
+
+ qreply(pQueue, pBindMsg);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Prepare DLPI notifications request.
+ *
+ * @returns VBox status code.
+ * @param pQueue Pointer to the read queue.
+ */
+static int vboxNetFltSolarisNotifyReq(queue_t *pQueue)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisNotifyReq\n"));
+
+ mblk_t *pNotifyMsg = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
+ if (RT_UNLIKELY(!pNotifyMsg))
+ return VERR_NO_MEMORY;
+
+ dl_notify_req_t *pNotifyReq = (dl_notify_req_t *)pNotifyMsg->b_rptr;
+ pNotifyReq->dl_notifications = DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_PHYS_ADDR;
+
+ qreply(pQueue, pNotifyMsg);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Opens the required device and returns the vnode_t associated with it.
+ * We require this for the funny attach/detach routine.
+ *
+ * @returns VBox status code.
+ * @param pszDev The device path.
+ * @param ppVNode Where to store the vnode_t pointer associated with the opened device.
+ * @param ppVNodeHeld Where to store the vnode_t required during closing of the device.
+ * @param ppUser Open handle required while closing the device.
+ */
+static int vboxNetFltSolarisOpenDev(char *pszDev, vnode_t **ppVNode, vnode_t **ppVNodeHeld, TIUSER **ppUser)
+{
+ int rc;
+ vnode_t *pVNodeHeld = NULL;
+ rc = lookupname(pszDev, UIO_SYSSPACE, FOLLOW, NULLVPP, &pVNodeHeld);
+ if (!rc)
+ {
+ TIUSER *pUser;
+ rc = t_kopen((file_t *)NULL, pVNodeHeld->v_rdev, FREAD | FWRITE, &pUser, kcred);
+ if (!rc)
+ {
+ *ppVNode = pUser->fp->f_vnode;
+ *ppVNodeHeld = pVNodeHeld;
+ *ppUser = pUser;
+ return VINF_SUCCESS;
+ }
+ VN_RELE(pVNodeHeld);
+ }
+ return VERR_PATH_NOT_FOUND;
+}
+
+
+/**
+ * Close the device opened using vboxNetFltSolarisOpenDev.
+ *
+ * @param pVNodeHeld Pointer to the held vnode of the device.
+ * @param pUser Pointer to the file handle.
+ */
+static void vboxNetFltSolarisCloseDev(vnode_t *pVNodeHeld, TIUSER *pUser)
+{
+ t_kclose(pUser, 0);
+ VN_RELE(pVNodeHeld);
+}
+
+
+/**
+ * Get the logical interface flags from the stream.
+ *
+ * @returns VBox status code.
+ * @param hDevice Layered device handle.
+ * @param pInterface Pointer to the interface.
+ */
+static int vboxNetFltSolarisGetIfFlags(ldi_handle_t hDevice, struct lifreq *pInterface)
+{
+ struct strioctl IOCReq;
+ int rc;
+ int ret;
+ IOCReq.ic_cmd = SIOCGLIFFLAGS;
+ IOCReq.ic_timout = 40;
+ IOCReq.ic_len = sizeof(struct lifreq);
+ IOCReq.ic_dp = (caddr_t)pInterface;
+ rc = ldi_ioctl(hDevice, I_STR, (intptr_t)&IOCReq, FKIOCTL, kcred, &ret);
+ if (!rc)
+ return VINF_SUCCESS;
+
+ return RTErrConvertFromErrno(rc);
+}
+
+
+/**
+ * Sets the multiplexor ID from the interface.
+ *
+ * @returns VBox status code.
+ * @param pVNode Pointer to the device vnode.
+ * @param pInterface Pointer to the interface.
+ */
+static int vboxNetFltSolarisSetMuxId(vnode_t *pVNode, struct lifreq *pInterface)
+{
+ struct strioctl IOCReq;
+ int rc;
+ int ret;
+ IOCReq.ic_cmd = SIOCSLIFMUXID;
+ IOCReq.ic_timout = 40;
+ IOCReq.ic_len = sizeof(struct lifreq);
+ IOCReq.ic_dp = (caddr_t)pInterface;
+
+ rc = strioctl(pVNode, I_STR, (intptr_t)&IOCReq, 0, K_TO_K, kcred, &ret);
+ if (!rc)
+ return VINF_SUCCESS;
+
+ return RTErrConvertFromErrno(rc);
+}
+
+
+/**
+ * Get the multiplexor file descriptor of the lower stream.
+ *
+ * @returns VBox status code.
+ * @param MuxId The multiplexor ID.
+ * @param pFd Where to store the lower stream file descriptor.
+ */
+static int vboxNetFltSolarisMuxIdToFd(vnode_t *pVNode, int MuxId, int *pFd)
+{
+ int ret;
+ int rc = strioctl(pVNode, _I_MUXID2FD, (intptr_t)MuxId, 0, K_TO_K, kcred, &ret);
+ if (!rc)
+ {
+ *pFd = ret;
+ return VINF_SUCCESS;
+ }
+
+ return RTErrConvertFromErrno(rc);
+}
+
+
+/**
+ * Relinks the lower and the upper IPv4 stream.
+ *
+ * @returns VBox status code.
+ * @param pVNode Pointer to the device vnode.
+ * @param pInterface Pointer to the interface.
+ * @param IpMuxFd The IP multiplexor ID.
+ * @param ArpMuxFd The ARP multiplexor ID.
+ */
+static int vboxNetFltSolarisRelinkIp4(vnode_t *pVNode, struct lifreq *pInterface, int IpMuxFd, int ArpMuxFd)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: pVNode=%p pInterface=%p IpMuxFd=%d ArpMuxFd=%d\n", pVNode,
+ pInterface, IpMuxFd, ArpMuxFd));
+
+ int NewIpMuxId;
+ int NewArpMuxId;
+ int rc = strioctl(pVNode, I_PLINK, (intptr_t)IpMuxFd, 0, K_TO_K, kcred, &NewIpMuxId);
+ int rc2 = strioctl(pVNode, I_PLINK, (intptr_t)ArpMuxFd, 0, K_TO_K, kcred, &NewArpMuxId);
+ if ( !rc
+ && !rc2)
+ {
+ pInterface->lifr_ip_muxid = NewIpMuxId;
+ pInterface->lifr_arp_muxid = NewArpMuxId;
+ rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to set new Mux Id.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp4: failed to link.\n"));
+
+ return VERR_GENERAL_FAILURE;
+}
+
+
+/**
+ * Relinks the lower and the upper IPv6 stream.
+ *
+ * @returns VBox status code.
+ * @param pVNode Pointer to the device vnode.
+ * @param pInterface Pointer to the interface.
+ * @param Ip6MuxFd The IPv6 multiplexor ID.
+ */
+static int vboxNetFltSolarisRelinkIp6(vnode_t *pVNode, struct lifreq *pInterface, int Ip6MuxFd)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: pVNode=%p pInterface=%p Ip6MuxFd=%d\n", pVNode, pInterface, Ip6MuxFd));
+
+ int NewIp6MuxId;
+ int rc = strioctl(pVNode, I_PLINK, (intptr_t)Ip6MuxFd, 0, K_TO_K, kcred, &NewIp6MuxId);
+ if (!rc)
+ {
+ pInterface->lifr_ip_muxid = NewIp6MuxId;
+ rc = vboxNetFltSolarisSetMuxId(pVNode, pInterface);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to set new Mux Id.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisRelinkIp6: failed to link.\n"));
+
+ return VERR_GENERAL_FAILURE;
+}
+
+
+/**
+ * Dynamically find the position on the host stack where to attach/detach ourselves.
+ *
+ * @returns VBox status code.
+ * @param pVNode Pointer to the lower stream vnode.
+ * @param pModPos Where to store the module position.
+ */
+static int vboxNetFltSolarisDetermineModPos(bool fAttach, vnode_t *pVNode, int *pModPos)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: fAttach=%d pVNode=%p pModPos=%p\n", fAttach, pVNode, pModPos));
+
+ int cMod;
+ int rc = strioctl(pVNode, I_LIST, (intptr_t)NULL, 0, K_TO_K, kcred, &cMod);
+ if (!rc)
+ {
+ if (cMod < 1)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: too few modules on host interface. cMod=%d\n"));
+ return VERR_OUT_OF_RANGE;
+ }
+
+ /*
+ * While attaching we make sure we are at the bottom most of the stack, excepting
+ * the host driver.
+ */
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: cMod=%d\n", cMod));
+ if (fAttach)
+ {
+ *pModPos = cMod - 1;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Detaching is a bit more complicated; since user could have altered the stack positions
+ * we take the safe approach by finding our position.
+ */
+ struct str_list StrList;
+ StrList.sl_nmods = cMod;
+ StrList.sl_modlist = RTMemAllocZ(cMod * sizeof(struct str_list));
+ if (RT_UNLIKELY(!StrList.sl_modlist))
+ {
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to alloc memory for StrList.\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Get the list of all modules on the stack.
+ */
+ int ret;
+ rc = strioctl(pVNode, I_LIST, (intptr_t)&StrList, 0, K_TO_K, kcred, &ret);
+ if (!rc)
+ {
+ /*
+ * Find our filter.
+ */
+ for (int i = 0; i < StrList.sl_nmods; i++)
+ {
+ if (!strcmp(DEVICE_NAME, StrList.sl_modlist[i].l_name))
+ {
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: Success! Found %s at %d.\n", DEVICE_NAME, i));
+ *pModPos = i;
+ RTMemFree(StrList.sl_modlist);
+ return VINF_SUCCESS;
+ }
+ }
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to find %s in the host stack.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get module information. rc=%d\n"));
+
+ RTMemFree(StrList.sl_modlist);
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisDetermineModPos: failed to get list of modules on host interface. rc=%d\n", rc));
+ return VERR_GENERAL_FAILURE;
+}
+
+
+/**
+ * Opens up dedicated stream on top of the interface.
+ * As a side-effect, the stream gets opened during
+ * the I_PUSH phase.
+ *
+ * @param pThis The instance.
+ */
+static int vboxNetFltSolarisOpenStream(PVBOXNETFLTINS pThis)
+{
+ ldi_ident_t DevId;
+ DevId = ldi_ident_from_anon();
+ int ret;
+
+ /** @todo support DLPI style 2.*/
+ /*
+ * Try style-1 open first.
+ */
+ char szDev[128];
+ RTStrPrintf(szDev, sizeof(szDev), "/dev/net/%s", pThis->szName);
+ int rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
+ if ( rc
+ && rc == ENODEV) /* ENODEV is returned when resolvepath fails, not ENOENT */
+ {
+ /*
+ * Fallback to non-ClearView style-1 open.
+ */
+ RTStrPrintf(szDev, sizeof(szDev), "/dev/%s", pThis->szName);
+ rc = ldi_open_by_name(szDev, FREAD | FWRITE, kcred, &pThis->u.s.hIface, DevId);
+ }
+
+ ldi_ident_release(DevId);
+ if (rc)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to open '%s' rc=%d pszName='%s'\n", szDev, rc, pThis->szName));
+ return VERR_INTNET_FLT_IF_FAILED;
+ }
+
+ rc = ldi_ioctl(pThis->u.s.hIface, I_FIND, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
+ if (!rc)
+ {
+ if (!ret)
+ {
+ g_VBoxNetFltSolarisInstance = pThis;
+ g_VBoxNetFltSolarisStreamType = kPromiscStream;
+
+ rc = ldi_ioctl(pThis->u.s.hIface, I_PUSH, (intptr_t)DEVICE_NAME, FKIOCTL, kcred, &ret);
+
+ g_VBoxNetFltSolarisInstance = NULL;
+ g_VBoxNetFltSolarisStreamType = kUndefined;
+
+ if (!rc)
+ return VINF_SUCCESS;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to push filter onto host interface '%s'\n", pThis->szName));
+ }
+ else
+ return VINF_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisOpenStream Failed to search for filter in interface '%s'.\n", pThis->szName));
+
+ return VERR_INTNET_FLT_IF_FAILED;
+}
+
+
+/**
+ * Closes the interface, thereby closing the dedicated stream.
+ *
+ * @param pThis The instance.
+ */
+static void vboxNetFltSolarisCloseStream(PVBOXNETFLTINS pThis)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisCloseStream pThis=%p\n"));
+
+ vboxNetFltRetain(pThis, false /* fBusy */);
+
+ ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
+}
+
+
+/**
+ * Dynamically attach under IPv4 and ARP streams on the host stack.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param fAttach Is this an attach or detach.
+ */
+static int vboxNetFltSolarisAttachIp4(PVBOXNETFLTINS pThis, bool fAttach)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp4 pThis=%p fAttach=%d\n", pThis, fAttach));
+
+ /*
+ * Statuatory Warning: Hackish code ahead.
+ */
+ char *pszModName = DEVICE_NAME;
+
+ struct lifreq Ip4Interface;
+ bzero(&Ip4Interface, sizeof(Ip4Interface));
+ Ip4Interface.lifr_addr.ss_family = AF_INET;
+ strncpy(Ip4Interface.lifr_name, pThis->szName, sizeof(Ip4Interface.lifr_name));
+
+ struct strmodconf StrMod;
+ StrMod.mod_name = pszModName;
+ StrMod.pos = -1; /* this is filled in later. */
+
+ struct strmodconf ArpStrMod;
+ bcopy(&StrMod, &ArpStrMod, sizeof(StrMod));
+
+ int rc;
+ int rc2;
+ int ret;
+ ldi_ident_t DeviceIdent = ldi_ident_from_anon();
+ ldi_handle_t Ip4DevHandle;
+ ldi_handle_t ArpDevHandle;
+
+ /*
+ * Open the IP and ARP streams as layered devices.
+ */
+ rc = ldi_open_by_name(IP_DEV_NAME, FREAD | FWRITE, kcred, &Ip4DevHandle, DeviceIdent);
+ if (rc)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the IP stream on '%s'.\n", pThis->szName));
+ ldi_ident_release(DeviceIdent);
+ return VERR_INTNET_FLT_IF_FAILED;
+ }
+
+ rc = ldi_open_by_name("/dev/arp", FREAD | FWRITE, kcred, &ArpDevHandle, DeviceIdent);
+ if (rc)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open the ARP stream on '%s'.\n", pThis->szName));
+ ldi_ident_release(DeviceIdent);
+ ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
+ return VERR_INTNET_FLT_IF_FAILED;
+ }
+
+ ldi_ident_release(DeviceIdent);
+
+ /*
+ * Obtain the interface flags from IPv4.
+ */
+ rc = vboxNetFltSolarisGetIfFlags(Ip4DevHandle, &Ip4Interface);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
+ * things that are not possible from the layered interface.
+ */
+ vnode_t *pUdp4VNode = NULL;
+ vnode_t *pUdp4VNodeHeld = NULL;
+ TIUSER *pUdp4User = NULL;
+ rc = vboxNetFltSolarisOpenDev(UDP_DEV_NAME, &pUdp4VNode, &pUdp4VNodeHeld, &pUdp4User);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the multiplexor IDs.
+ */
+ rc = ldi_ioctl(Ip4DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip4Interface, FKIOCTL, kcred, &ret);
+ if (!rc)
+ {
+ /*
+ * Get the multiplex file descriptor to the lower streams. Generally this is lost
+ * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
+ */
+ int Ip4MuxFd;
+ int ArpMuxFd;
+ rc = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_ip_muxid, &Ip4MuxFd);
+ rc2 = vboxNetFltSolarisMuxIdToFd(pUdp4VNode, Ip4Interface.lifr_arp_muxid, &ArpMuxFd);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(rc2))
+ {
+ /*
+ * We need to I_PUNLINK on these multiplexor IDs before we can start
+ * operating on the lower stream as insertions are direct operations on the lower stream.
+ */
+ int ret;
+ rc = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
+ rc2 = strioctl(pUdp4VNode, I_PUNLINK, (intptr_t)Ip4Interface.lifr_arp_muxid, 0, K_TO_K, kcred, &ret);
+ if ( !rc
+ && !rc2)
+ {
+ /*
+ * Obtain the vnode from the useless userland file descriptor.
+ */
+ file_t *pIpFile = getf(Ip4MuxFd);
+ file_t *pArpFile = getf(ArpMuxFd);
+ if ( pIpFile
+ && pArpFile
+ && pArpFile->f_vnode
+ && pIpFile->f_vnode)
+ {
+ vnode_t *pIp4VNode = pIpFile->f_vnode;
+ vnode_t *pArpVNode = pArpFile->f_vnode;
+
+ /*
+ * Find the position on the host stack for attaching/detaching ourselves.
+ */
+ rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp4VNode, &StrMod.pos);
+ rc2 = vboxNetFltSolarisDetermineModPos(fAttach, pArpVNode, &ArpStrMod.pos);
+ if ( RT_SUCCESS(rc)
+ && RT_SUCCESS(rc2))
+ {
+ /*
+ * Inject/Eject from the host IP stack.
+ */
+ if (!fAttach)
+ vboxNetFltRetain(pThis, false /* fBusy */);
+
+ /*
+ * Set global data which will be grabbed by ModOpen.
+ * There is a known (though very unlikely) race here because
+ * of the inability to pass user data while inserting.
+ */
+ g_VBoxNetFltSolarisInstance = pThis;
+ g_VBoxNetFltSolarisStreamType = kIp4Stream;
+
+ rc = strioctl(pIp4VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
+ kcred, &ret);
+
+ g_VBoxNetFltSolarisInstance = NULL;
+ g_VBoxNetFltSolarisStreamType = kUndefined;
+
+ if (!rc)
+ {
+ if (!fAttach)
+ vboxNetFltRetain(pThis, false /* fBusy */);
+
+ /*
+ * Inject/Eject from the host ARP stack.
+ */
+ g_VBoxNetFltSolarisInstance = pThis;
+ g_VBoxNetFltSolarisStreamType = kArpStream;
+
+ rc = strioctl(pArpVNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&ArpStrMod, 0, K_TO_K,
+ kcred, &ret);
+
+ g_VBoxNetFltSolarisInstance = NULL;
+ g_VBoxNetFltSolarisStreamType = kUndefined;
+
+ if (!rc)
+ {
+ /*
+ * Our job's not yet over; we need to relink the upper and lower streams
+ * otherwise we've pretty much screwed up the host interface.
+ */
+ rc = vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Close the devices ONLY during the return from function case; otherwise
+ * we end up close twice which is an instant kernel panic.
+ */
+ vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
+ ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
+ ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Success! %s %s@(IPv4:%d Arp:%d) "
+ "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
+ StrMod.pos, ArpStrMod.pos, fAttach ? "to" : "from", pThis->szName));
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Relinking failed. Mode=%s rc=%d.\n",
+ fAttach ? "inject" : "eject", rc));
+ }
+
+ /*
+ * Try failing gracefully during attach.
+ */
+ if (fAttach)
+ strioctl(pArpVNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the ARP stack. rc=%d\n",
+ fAttach ? "inject into" : "eject from", rc));
+ }
+
+ if (fAttach)
+ strioctl(pIp4VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
+
+ vboxNetFltSolarisRelinkIp4(pUdp4VNode, &Ip4Interface, Ip4MuxFd, ArpMuxFd);
+
+ if (!fAttach)
+ vboxNetFltRelease(pThis, false /* fBusy */);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to %s the IP stack. rc=%d\n",
+ fAttach ? "inject into" : "eject from", rc));
+ }
+
+ g_VBoxNetFltSolarisInstance = NULL;
+ g_VBoxNetFltSolarisStreamType = kUndefined;
+
+ if (!fAttach)
+ vboxNetFltRelease(pThis, false /* fBusy */);
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to find position. rc=%d rc2=%d\n", rc, rc2));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get vnode from MuxFd.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to get Mux Ids. rc=%d\n", rc));
+ vboxNetFltSolarisCloseDev(pUdp4VNodeHeld, pUdp4User);
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: failed to open UDP. rc=%d\n", rc));
+ }
+ else
+ {
+ /*
+ * This would happen for interfaces that are not plumbed.
+ */
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp4: Warning: seems '%s' is unplumbed.\n", pThis->szName));
+ rc = VINF_SUCCESS;
+ }
+
+ ldi_close(ArpDevHandle, FREAD | FWRITE, kcred);
+ ldi_close(Ip4DevHandle, FREAD | FWRITE, kcred);
+
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ return VERR_INTNET_FLT_IF_FAILED;
+}
+
+
+/**
+ * Dynamically attach under IPv6 on the host stack.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param fAttach Is this an attach or detach.
+ */
+static int vboxNetFltSolarisAttachIp6(PVBOXNETFLTINS pThis, bool fAttach)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp6 pThis=%p fAttach=%d\n", pThis, fAttach));
+
+ /*
+ * Statuatory Warning: Hackish code ahead.
+ */
+ char *pszModName = DEVICE_NAME;
+
+ struct lifreq Ip6Interface;
+ bzero(&Ip6Interface, sizeof(Ip6Interface));
+ Ip6Interface.lifr_addr.ss_family = AF_INET6;
+ strncpy(Ip6Interface.lifr_name, pThis->szName, sizeof(Ip6Interface.lifr_name));
+
+ struct strmodconf StrMod;
+ StrMod.mod_name = pszModName;
+ StrMod.pos = -1; /* this is filled in later. */
+
+ int rc;
+ int rc2;
+ int ret;
+ ldi_ident_t DeviceIdent = ldi_ident_from_anon();
+ ldi_handle_t Ip6DevHandle;
+ ldi_handle_t Udp6DevHandle;
+
+ /*
+ * Open the IPv6 stream as a layered devices.
+ */
+ rc = ldi_open_by_name(IP6_DEV_NAME, FREAD | FWRITE, kcred, &Ip6DevHandle, DeviceIdent);
+ ldi_ident_release(DeviceIdent);
+ if (rc)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open the IPv6 stream on '%s'.\n", pThis->szName));
+ return VERR_INTNET_FLT_IF_FAILED;
+ }
+
+ /*
+ * Obtain the interface flags from IPv6.
+ */
+ rc = vboxNetFltSolarisGetIfFlags(Ip6DevHandle, &Ip6Interface);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Open the UDP stream. We sort of cheat here and obtain the vnode so that we can perform
+ * things that are not possible from the layered interface.
+ */
+ vnode_t *pUdp6VNode = NULL;
+ vnode_t *pUdp6VNodeHeld = NULL;
+ TIUSER *pUdp6User = NULL;
+ rc = vboxNetFltSolarisOpenDev(UDP6_DEV_NAME, &pUdp6VNode, &pUdp6VNodeHeld, &pUdp6User);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Get the multiplexor IDs.
+ */
+ rc = ldi_ioctl(Ip6DevHandle, SIOCGLIFMUXID, (intptr_t)&Ip6Interface, FKIOCTL, kcred, &ret);
+ if (!rc)
+ {
+ /*
+ * Get the multiplex file descriptor to the lower streams. Generally this is lost
+ * once a module is I_PLINK, we need to reobtain it for inserting/removing ourselves from the stack.
+ */
+ int Ip6MuxFd;
+ rc = vboxNetFltSolarisMuxIdToFd(pUdp6VNode, Ip6Interface.lifr_ip_muxid, &Ip6MuxFd);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * We need to I_PUNLINK on these multiplexor IDs before we can start
+ * operating on the lower stream as insertions are direct operations on the lower stream.
+ */
+ int ret;
+ rc = strioctl(pUdp6VNode, I_PUNLINK, (intptr_t)Ip6Interface.lifr_ip_muxid, 0, K_TO_K, kcred, &ret);
+ if (!rc)
+ {
+ /*
+ * Obtain the vnode from the useless userland file descriptor.
+ */
+ file_t *pIpFile = getf(Ip6MuxFd);
+ if ( pIpFile
+ && pIpFile->f_vnode)
+ {
+ vnode_t *pIp6VNode = pIpFile->f_vnode;
+
+ /*
+ * Find the position on the host stack for attaching/detaching ourselves.
+ */
+ rc = vboxNetFltSolarisDetermineModPos(fAttach, pIp6VNode, &StrMod.pos);
+ if (RT_SUCCESS(rc))
+ {
+ if (!fAttach)
+ vboxNetFltRetain(pThis, false /* fBusy */);
+
+ /*
+ * Set global data which will be grabbed by ModOpen.
+ * There is a known (though very unlikely) race here because
+ * of the inability to pass user data while inserting.
+ */
+ g_VBoxNetFltSolarisInstance = pThis;
+ g_VBoxNetFltSolarisStreamType = kIp6Stream;
+
+ /*
+ * Inject/Eject from the host IPv6 stack.
+ */
+ rc = strioctl(pIp6VNode, fAttach ? _I_INSERT : _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K,
+ kcred, &ret);
+ if (!rc)
+ {
+ g_VBoxNetFltSolarisInstance = NULL;
+ g_VBoxNetFltSolarisStreamType = kUndefined;
+
+ /*
+ * Our job's not yet over; we need to relink the upper and lower streams
+ * otherwise we've pretty much screwed up the host interface.
+ */
+ rc = vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Close the devices ONLY during the return from function case; otherwise
+ * we end up close twice which is an instant kernel panic.
+ */
+ vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
+ ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Success! %s %s@(IPv6:%d) "
+ "%s interface %s\n", fAttach ? "Injected" : "Ejected", StrMod.mod_name,
+ StrMod.pos, fAttach ? "to" : "from", pThis->szName));
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: Relinking failed. Mode=%s rc=%d.\n",
+ fAttach ? "inject" : "eject", rc));
+ }
+
+ if (fAttach)
+ strioctl(pIp6VNode, _I_REMOVE, (intptr_t)&StrMod, 0, K_TO_K, kcred, &ret);
+
+ vboxNetFltSolarisRelinkIp6(pUdp6VNode, &Ip6Interface, Ip6MuxFd);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to %s the IP stack. rc=%d\n",
+ fAttach ? "inject into" : "eject from", rc));
+ if (!fAttach)
+ vboxNetFltRelease(pThis, false /* fBusy */);
+ }
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to find position. rc=%d rc2=%d\n", rc, rc2));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get vnode from MuxFd.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to unlink upper stream rc=%d rc2=%d.\n", rc, rc2));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get MuxFd from MuxId. rc=%d rc2=%d\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get Mux Ids. rc=%d\n", rc));
+ vboxNetFltSolarisCloseDev(pUdp6VNodeHeld, pUdp6User);
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to open UDP. rc=%d\n", rc));
+ }
+ else
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAttachIp6: failed to get IPv6 flags.\n", pThis->szName));
+
+ ldi_close(Ip6DevHandle, FREAD | FWRITE, kcred);
+
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ return VERR_INTNET_FLT_IF_FAILED;
+}
+
+
+/**
+ * Wrapper for attaching ourselves to the interface.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ */
+static int vboxNetFltSolarisAttachToInterface(PVBOXNETFLTINS pThis)
+{
+ int rc = vboxNetFltSolarisOpenStream(pThis);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltSolarisAttachIp4(pThis, true /* fAttach */);
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetFltSolarisAttachIp6(pThis, true /* fAttach */);
+ /* Ignore Ipv6 binding errors as it's optional. */
+
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, false);
+ }
+ else
+ vboxNetFltSolarisCloseStream(pThis);
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface vboxNetFltSolarisOpenStream failed rc=%Rrc\n", rc));
+
+ return rc;
+}
+
+
+/**
+ * Wrapper for detaching ourselves from the interface.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @remarks Owns the globals mutex, so re-requesting it anytime during this phase
+ * would panic the system (e.g. in vboxNetFltSolarisFindInstance).
+ */
+static int vboxNetFltSolarisDetachFromInterface(PVBOXNETFLTINS pThis)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisDetachFromInterface pThis=%p\n", pThis));
+
+ ASMAtomicWriteBool(&pThis->fDisconnectedFromHost, true);
+ vboxNetFltSolarisCloseStream(pThis);
+ int rc = vboxNetFltSolarisAttachIp4(pThis, false /* fAttach */);
+ if (pThis->u.s.pvIp6Stream)
+ rc = vboxNetFltSolarisAttachIp6(pThis, false /* fAttach */);
+
+ return rc;
+}
+
+
+/**
+ * Create a solaris message block from the SG list.
+ *
+ * @returns Solaris message block.
+ * @param pThis The instance.
+ * @param pSG Pointer to the scatter-gather list.
+ */
+static mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n"));
+
+ mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_MED);
+ if (RT_UNLIKELY(!pMsg))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
+ return NULL;
+ }
+
+ /*
+ * Single buffer copy. Maybe later explore the
+ * need/possibility for using a mblk_t chain rather.
+ */
+ for (unsigned i = 0; i < pSG->cSegsUsed; i++)
+ {
+ if (pSG->aSegs[i].pv)
+ {
+ bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
+ pMsg->b_wptr += pSG->aSegs[i].cb;
+ }
+ }
+ DB_TYPE(pMsg) = M_DATA;
+ return pMsg;
+}
+
+
+/**
+ * Calculate the number of segments required for this message block.
+ *
+ * @returns Number of segments.
+ * @param pThis The instance
+ * @param pMsg Pointer to the data message.
+ */
+static unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
+{
+ unsigned cSegs = 0;
+ for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
+ if (MBLKL(pCur))
+ cSegs++;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ if (msgdsize(pMsg) < 60)
+ cSegs++;
+#endif
+
+ NOREF(pThis);
+ return RT_MAX(cSegs, 1);
+}
+
+
+/**
+ * Initializes an SG list from the given message block.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param pMsg Pointer to the data message.
+ The caller must ensure it's not a control message block.
+ * @param pSG Pointer to the SG.
+ * @param cSegs Number of segments in the SG.
+ * This should match the number in the message block exactly!
+ * @param fSrc The source of the message.
+ */
+static int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
+
+ pSG->pvOwnerData = NULL;
+ pSG->pvUserData = NULL;
+ pSG->pvUserData2 = NULL;
+ pSG->cUsers = 1;
+ pSG->cbTotal = 0;
+ pSG->fFlags = INTNETSG_FLAGS_TEMP;
+ pSG->cSegsAlloc = cSegs;
+
+ /*
+ * Convert the message block to segments.
+ */
+ mblk_t *pCur = pMsg;
+ unsigned iSeg = 0;
+ while (pCur)
+ {
+ size_t cbSeg = MBLKL(pCur);
+ if (cbSeg)
+ {
+ void *pvSeg = pCur->b_rptr;
+ pSG->aSegs[iSeg].pv = pvSeg;
+ pSG->aSegs[iSeg].cb = cbSeg;
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ pSG->cbTotal += cbSeg;
+ iSeg++;
+ }
+ pCur = pCur->b_cont;
+ }
+ pSG->cSegsUsed = iSeg;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
+ {
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
+
+ static uint8_t const s_abZero[128] = {0};
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
+ pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
+ pSG->cbTotal = 60;
+ pSG->cSegsUsed++;
+ }
+#endif
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Converts raw mode M_DATA messages to M_PROTO DL_UNITDATA_IND format.
+ *
+ * @returns VBox status code.
+ * @param pMsg Pointer to the raw message.
+ * @param pDlpiMsg Where to store the M_PROTO message.
+ *
+ * @remarks The original raw message would be no longer valid and will be
+ * linked as part of the new DLPI message. Callers must take care
+ * not to use the raw message if this routine is successful.
+ */
+static int vboxNetFltSolarisRawToUnitData(mblk_t *pMsg, mblk_t **ppDlpiMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData pMsg=%p\n", pMsg));
+
+ if (DB_TYPE(pMsg) != M_DATA)
+ return VERR_NO_MEMORY;
+
+ size_t cbMsg = sizeof(dl_unitdata_ind_t) + 2 * sizeof(vboxnetflt_dladdr_t);
+ mblk_t *pDlpiMsg = allocb(cbMsg, BPRI_MED);
+ if (RT_UNLIKELY(!pDlpiMsg))
+ return VERR_NO_MEMORY;
+
+ DB_TYPE(pDlpiMsg) = M_PROTO;
+ dl_unitdata_ind_t *pDlpiData = (dl_unitdata_ind_t *)pDlpiMsg->b_rptr;
+ pDlpiData->dl_primitive = DL_UNITDATA_IND;
+ pDlpiData->dl_dest_addr_length = VBOXNETFLT_DLADDRL;
+ pDlpiData->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
+ pDlpiData->dl_src_addr_length = VBOXNETFLT_DLADDRL;
+ pDlpiData->dl_src_addr_offset = VBOXNETFLT_DLADDRL + sizeof(dl_unitdata_ind_t);
+
+ PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
+
+ vboxnetflt_dladdr_t *pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_dest_addr_offset);
+ pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
+ bcopy(&pEthHdr->DstMac, &pDlAddr->Mac, sizeof(RTMAC));
+
+ pDlAddr = (vboxnetflt_dladdr_t *)(pDlpiMsg->b_rptr + pDlpiData->dl_src_addr_offset);
+ pDlAddr->SAP = RT_BE2H_U16(pEthHdr->EtherType);
+ bcopy(&pEthHdr->SrcMac, &pDlAddr->Mac, sizeof(RTMAC));
+
+ pDlpiMsg->b_wptr = pDlpiMsg->b_rptr + cbMsg;
+
+ /* Make the message point to the protocol header */
+ pMsg->b_rptr += sizeof(RTNETETHERHDR);
+
+ pDlpiMsg->b_cont = pMsg;
+ *ppDlpiMsg = pDlpiMsg;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Converts DLPI M_PROTO messages to the raw mode M_DATA format.
+ *
+ * @returns VBox status code.
+ * @param pMsg Pointer to the M_PROTO message.
+ * @param ppRawMsg Where to store the converted message.
+ *
+ * @remarks If successful, the original pMsg is no longer valid, it will be deleted.
+ * Callers must take care not to continue to use pMsg after a successful
+ * call to this conversion routine.
+ */
+static int vboxNetFltSolarisUnitDataToRaw(PVBOXNETFLTINS pThis, mblk_t *pMsg, mblk_t **ppRawMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw pMsg=%p\n", pMsg));
+
+ if ( !pMsg->b_cont
+ || DB_TYPE(pMsg) != M_PROTO)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw invalid input message.\n"));
+ return VERR_NET_PROTOCOL_ERROR;
+ }
+
+ /*
+ * Upstream consumers send/receive packets in the fast path mode.
+ * We of course need to convert them into raw ethernet frames.
+ */
+ RTNETETHERHDR EthHdr;
+ union DL_primitives *pPrim = (union DL_primitives *)pMsg->b_rptr;
+ switch (pPrim->dl_primitive)
+ {
+ case DL_UNITDATA_IND:
+ {
+ /*
+ * Receive side.
+ */
+ dl_unitdata_ind_t *pDlpiMsg = (dl_unitdata_ind_t *)pMsg->b_rptr;
+ bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
+ bcopy(pMsg->b_rptr + pDlpiMsg->dl_src_addr_offset, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
+
+ vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
+ EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
+
+ break;
+ }
+
+ case DL_UNITDATA_REQ:
+ {
+ /*
+ * Send side.
+ */
+ dl_unitdata_req_t *pDlpiMsg = (dl_unitdata_req_t *)pMsg->b_rptr;
+
+ bcopy(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset, &EthHdr.DstMac, sizeof(EthHdr.DstMac));
+ bcopy(&pThis->u.s.Mac, &EthHdr.SrcMac, sizeof(EthHdr.SrcMac));
+
+ vboxnetflt_dladdr_t *pDLSapAddr = (vboxnetflt_dladdr_t *)(pMsg->b_rptr + pDlpiMsg->dl_dest_addr_offset);
+ EthHdr.EtherType = RT_H2BE_U16(pDLSapAddr->SAP);
+
+ break;
+ }
+
+ default:
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisUnitDataToRaw Unknown M_PROTO. This shouldn't be happening!!"));
+ return VERR_NET_PROTOCOL_ERROR;
+ }
+ }
+
+ /*
+ * Let us just link it as a mblk_t chain rather than re-copy the entire message.
+ * The vboxNetFltSolarisMBlkToSG function will handle chained mblk_t's.
+ */
+ size_t cbLen = sizeof(EthHdr);
+ mblk_t *pEtherMsg = allocb(cbLen, BPRI_MED);
+ if (RT_UNLIKELY(!pEtherMsg))
+ return VERR_NO_MEMORY;
+
+ DB_TYPE(pEtherMsg) = M_DATA;
+ bcopy(&EthHdr, pEtherMsg->b_wptr, sizeof(EthHdr));
+ pEtherMsg->b_wptr += cbLen;
+
+ pEtherMsg->b_cont = pMsg->b_cont;
+
+ /*
+ * Change the chained blocks to type M_DATA.
+ */
+ for (mblk_t *pTmp = pEtherMsg->b_cont; pTmp; pTmp = pTmp->b_cont)
+ DB_TYPE(pTmp) = M_DATA;
+
+ pMsg->b_cont = NULL;
+ freemsg(pMsg);
+
+ *ppRawMsg = pEtherMsg;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Initializes a packet identifier.
+ *
+ * @param pTag Pointer to the packed identifier.
+ * @param pMsg Pointer to the message to be identified.
+ *
+ * @remarks Warning!!! This function assumes 'pMsg' is an unchained message.
+ */
+static inline void vboxNetFltSolarisInitPacketId(PVBOXNETFLTPACKETID pTag, mblk_t *pMsg)
+{
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+ size_t cbMsg = MBLKL(pMsg);
+
+ pTag->cbPacket = cbMsg;
+ pTag->Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
+ bcopy(&pEthHdr->SrcMac, &pTag->SrcMac, sizeof(RTMAC));
+ bcopy(&pEthHdr->DstMac, &pTag->DstMac, sizeof(RTMAC));
+}
+
+
+/**
+ * Queues a packet for loopback elimination.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param pPromiscStream Pointer to the promiscuous stream.
+ * @param pMsg Pointer to the message.
+ */
+static int vboxNetFltSolarisQueueLoopback(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
+{
+ Assert(pThis);
+ Assert(pMsg);
+ Assert(DB_TYPE(pMsg) == M_DATA);
+ Assert(pPromiscStream);
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback pThis=%p pPromiscStream=%p pMsg=%p\n", pThis, pPromiscStream, pMsg));
+
+ if (RT_UNLIKELY(pMsg->b_cont))
+ {
+ /*
+ * We don't currently make chained messages in on Xmit
+ * so this only needs to be supported when we do that.
+ */
+ return VERR_NOT_SUPPORTED;
+ }
+
+ size_t cbMsg = MBLKL(pMsg);
+ if (RT_UNLIKELY(cbMsg < sizeof(RTNETETHERHDR)))
+ return VERR_NET_MSG_SIZE;
+
+ int rc = RTSemFastMutexRequest(pThis->u.s.hFastMtx);
+ AssertRCReturn(rc, rc);
+
+ PVBOXNETFLTPACKETID pCur = NULL;
+ if (pPromiscStream->cLoopback < VBOXNETFLT_LOOPBACK_SIZE
+ || ( pPromiscStream->pHead
+ && pPromiscStream->pHead->cbPacket == 0))
+ {
+ do
+ {
+ if (!pPromiscStream->pHead)
+ {
+ pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
+ if (RT_UNLIKELY(!pCur))
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ vboxNetFltSolarisInitPacketId(pCur, pMsg);
+
+ pCur->pNext = NULL;
+ pPromiscStream->pHead = pCur;
+ pPromiscStream->pTail = pCur;
+ pPromiscStream->cLoopback++;
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback initialized head. checksum=%u.\n",
+ pPromiscStream->pHead->Checksum));
+ break;
+ }
+ else if ( pPromiscStream->pHead
+ && pPromiscStream->pHead->cbPacket == 0)
+ {
+ pCur = pPromiscStream->pHead;
+ vboxNetFltSolarisInitPacketId(pCur, pMsg);
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback re-used head checksum=%u cLoopback=%d.\n",
+ pCur->Checksum, pPromiscStream->cLoopback));
+ break;
+ }
+ else
+ {
+ pCur = RTMemAlloc(sizeof(VBOXNETFLTPACKETID));
+ if (RT_UNLIKELY(!pCur))
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+
+ vboxNetFltSolarisInitPacketId(pCur, pMsg);
+
+ pCur->pNext = pPromiscStream->pHead;
+ pPromiscStream->pHead = pCur;
+ pPromiscStream->cLoopback++;
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback added head checksum=%u cLoopback=%d.\n", pCur->Checksum,
+ pPromiscStream->cLoopback));
+ break;
+ }
+ } while (0);
+ }
+ else
+ {
+ /*
+ * Maximum loopback queue size reached. Re-use tail as head.
+ */
+ Assert(pPromiscStream->pHead);
+ Assert(pPromiscStream->pTail);
+
+ /*
+ * Find tail's previous item.
+ */
+ PVBOXNETFLTPACKETID pPrev = NULL;
+ pCur = pPromiscStream->pHead;
+
+ /** @todo consider if this is worth switching to a double linked list... */
+ while (pCur != pPromiscStream->pTail)
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+
+ pPromiscStream->pTail = pPrev;
+ pPromiscStream->pTail->pNext = NULL;
+ pCur->pNext = pPromiscStream->pHead;
+ pPromiscStream->pHead = pCur;
+
+ vboxNetFltSolarisInitPacketId(pCur, pMsg);
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisQueueLoopback recycled tail!! checksum=%u cLoopback=%d\n", pCur->Checksum,
+ pPromiscStream->cLoopback));
+ }
+
+ RTSemFastMutexRelease(pThis->u.s.hFastMtx);
+
+ return rc;
+}
+
+
+/**
+ * Checks if the packet is enqueued for loopback as our own packet.
+ *
+ * @returns If it's our packet, returns true after dequeuing it, otherwise false.
+ * @param pThis The instance.
+ * @param pPromiscStream Pointer to the promiscuous stream.
+ * @param pMsg Pointer to the message.
+ */
+static bool vboxNetFltSolarisIsOurMBlk(PVBOXNETFLTINS pThis, vboxnetflt_promisc_stream_t *pPromiscStream, mblk_t *pMsg)
+{
+ Assert(pThis);
+ Assert(pPromiscStream);
+ Assert(pMsg);
+ Assert(DB_TYPE(pMsg) == M_DATA);
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk pThis=%p pMsg=%p\n", pThis, pMsg));
+
+ if (pMsg->b_cont)
+ {
+ /** Handle this when Xmit makes chained messages */
+ return false;
+ }
+
+ size_t cbMsg = MBLKL(pMsg);
+ if (cbMsg < sizeof(RTNETETHERHDR))
+ return false;
+
+ int rc = RTSemFastMutexRequest(pThis->u.s.hFastMtx);
+ AssertRCReturn(rc, rc);
+
+ PVBOXNETFLTPACKETID pPrev = NULL;
+ PVBOXNETFLTPACKETID pCur = pPromiscStream->pHead;
+ bool fIsOurPacket = false;
+ while (pCur)
+ {
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+ if ( pCur->cbPacket != cbMsg
+ || pCur->SrcMac.au8[0] != pEthHdr->SrcMac.au8[0]
+ || pCur->SrcMac.au8[1] != pEthHdr->SrcMac.au8[1]
+ || pCur->SrcMac.au8[2] != pEthHdr->SrcMac.au8[2]
+ || pCur->SrcMac.au8[3] != pEthHdr->SrcMac.au8[3]
+ || pCur->SrcMac.au8[4] != pEthHdr->SrcMac.au8[4]
+ || pCur->SrcMac.au8[5] != pEthHdr->SrcMac.au8[5]
+ || pCur->DstMac.au8[0] != pEthHdr->DstMac.au8[0]
+ || pCur->DstMac.au8[1] != pEthHdr->DstMac.au8[1]
+ || pCur->DstMac.au8[2] != pEthHdr->DstMac.au8[2]
+ || pCur->DstMac.au8[3] != pEthHdr->DstMac.au8[3]
+ || pCur->DstMac.au8[4] != pEthHdr->DstMac.au8[4]
+ || pCur->DstMac.au8[5] != pEthHdr->DstMac.au8[5])
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ continue;
+ }
+
+ uint16_t Checksum = RTCrc32(pMsg->b_rptr, cbMsg);
+ if (pCur->Checksum != Checksum)
+ {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ continue;
+ }
+
+ /*
+ * Yes, it really is our own packet, mark it as handled
+ * and move it as a "free slot" to the head and return success.
+ */
+ pCur->cbPacket = 0;
+ if (pPrev)
+ {
+ if (!pCur->pNext)
+ pPromiscStream->pTail = pPrev;
+
+ pPrev->pNext = pCur->pNext;
+ pCur->pNext = pPromiscStream->pHead;
+ pPromiscStream->pHead = pCur;
+ }
+ fIsOurPacket = true;
+
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisIsOurMBlk found packet %p Checksum=%u cLoopback=%d\n", pMsg, Checksum,
+ pPromiscStream->cLoopback));
+ break;
+ }
+
+ RTSemFastMutexRelease(pThis->u.s.hFastMtx);
+ return fIsOurPacket;
+}
+
+
+/**
+ * Worker for routing messages from the wire or from the host.
+ *
+ * @returns VBox status code.
+ * @param pThis The instance.
+ * @param pStream Pointer to the stream.
+ * @param pQueue Pointer to the read queue.
+ * @param pOrigMsg Pointer to the message.
+ */
+static int vboxNetFltSolarisRecv(PVBOXNETFLTINS pThis, vboxnetflt_stream_t *pStream, queue_t *pQueue, mblk_t *pMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pThis=%p pMsg=%p\n", pThis, pMsg));
+
+ AssertCompile(sizeof(struct ether_header) == sizeof(RTNETETHERHDR));
+ Assert(pStream->Type == kPromiscStream);
+
+ vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
+ if (RT_UNLIKELY(!pPromiscStream))
+ {
+ LogRel((DEVICE_NAME ":Promiscuous stream missing!! Failing to receive packet.\n"));
+ return VERR_INVALID_POINTER;
+ }
+
+ /*
+ * Don't loopback packets we transmit to the wire.
+ */
+ /** @todo maybe we need not check for loopback for INTNETTRUNKDIR_HOST case? */
+ if (vboxNetFltSolarisIsOurMBlk(pThis, pPromiscStream, pMsg))
+ {
+ LogFlow((DEVICE_NAME ":Avoiding packet loopback.\n"));
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Figure out the source of the packet based on the source Mac address.
+ */
+ uint32_t fSrc = INTNETTRUNKDIR_WIRE;
+ PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
+ if (vboxNetFltPortOsIsHostMac(pThis, &pEthHdr->SrcMac))
+ fSrc = INTNETTRUNKDIR_HOST;
+
+ /*
+ * Afaik; we no longer need to worry about incorrect checksums because we now use
+ * a dedicated stream and don't intercept packets under IP/ARP which might be doing
+ * checksum offloading.
+ */
+#if 0
+ if (fSrc & INTNETTRUNKDIR_HOST)
+ {
+ mblk_t *pCorrectedMsg = vboxNetFltSolarisFixChecksums(pMsg);
+ if (pCorrectedMsg)
+ pMsg = pCorrectedMsg;
+ }
+ vboxNetFltSolarisAnalyzeMBlk(pMsg);
+#endif
+
+ /*
+ * Route all received packets into the internal network.
+ */
+ unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pMsg);
+ PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+ int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
+ if (RT_SUCCESS(rc))
+ pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed. rc=%d\n", rc));
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Finalize the message to be fed into the internal network.
+ * Verifies and tries to fix checksums for TCP, UDP and IP.
+ *
+ * @returns Corrected message or NULL if no change was required.
+ * @param pMsg Pointer to the message block.
+ * This must not be DLPI linked messages, must be M_DATA.
+ *
+ * @remarks If this function returns a checksum adjusted message, the
+ * passed in input message has been freed and should not be
+ * referenced anymore by the caller.
+ */
+static mblk_t *vboxNetFltSolarisFixChecksums(mblk_t *pMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisFixChecksums pMsg=%p\n"));
+
+ Assert(DB_TYPE(pMsg) == M_DATA);
+
+ if (MBLKL(pMsg) < sizeof(RTNETETHERHDR))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums Packet shorter than ethernet header size!\n"));
+ return NULL;
+ }
+
+ PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
+ if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
+ {
+ /*
+ * Check if we have a complete packet or being fed a chain.
+ */
+ size_t cbIpPacket = 0;
+ mblk_t *pFullMsg = NULL;
+ if (pMsg->b_cont)
+ {
+ LogFlow((DEVICE_NAME ":Chained mblk_t.\n"));
+
+ /*
+ * Handle chain by making a packet copy to verify if the IP checksum is correct.
+ * Contributions to calculating IP checksums from a chained message block with
+ * odd/non-pulled up sizes are welcome.
+ */
+ size_t cbFullMsg = msgdsize(pMsg);
+ mblk_t *pFullMsg = allocb(cbFullMsg, BPRI_MED);
+ LogFlow((DEVICE_NAME ":msgdsize returns %d\n", cbFullMsg));
+ if (RT_UNLIKELY(!pFullMsg))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisFixChecksums failed to alloc new message of %d bytes.\n", cbFullMsg));
+ return NULL;
+ }
+
+ for (mblk_t *pTmp = pMsg; pTmp; pTmp = pTmp->b_cont)
+ {
+ if (DB_TYPE(pTmp) == M_DATA)
+ {
+ bcopy(pTmp->b_rptr, pFullMsg->b_wptr, MBLKL(pTmp));
+ pFullMsg->b_wptr += MBLKL(pTmp);
+ }
+ }
+
+ DB_TYPE(pFullMsg) = M_DATA;
+ pEthHdr = (PRTNETETHERHDR)pFullMsg->b_rptr;
+ cbIpPacket = MBLKL(pFullMsg) - sizeof(RTNETETHERHDR);
+ }
+ else
+ cbIpPacket = MBLKL(pMsg) - sizeof(RTNETETHERHDR);
+
+ /*
+ * Check if the IP checksum is valid.
+ */
+ uint8_t *pbProtocol = (uint8_t *)(pEthHdr + 1);
+ PRTNETIPV4 pIpHdr = (PRTNETIPV4)pbProtocol;
+ size_t cbPayload = cbIpPacket - (pIpHdr->ip_hl << 2);
+ bool fChecksumAdjusted = false;
+ if (RTNetIPv4IsHdrValid(pIpHdr, cbPayload, cbPayload))
+ {
+ pbProtocol += (pIpHdr->ip_hl << 2);
+
+ /*
+ * Fix up TCP/UDP and IP checksums if they're incomplete/invalid.
+ */
+ if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
+ {
+ PRTNETTCP pTcpHdr = (PRTNETTCP)pbProtocol;
+ uint16_t TcpChecksum = RTNetIPv4TCPChecksum(pIpHdr, pTcpHdr, NULL);
+ if (pTcpHdr->th_sum != TcpChecksum)
+ {
+ pTcpHdr->th_sum = TcpChecksum;
+ fChecksumAdjusted = true;
+ LogFlow((DEVICE_NAME ":fixed TCP checksum.\n"));
+ }
+ }
+ else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
+ {
+ PRTNETUDP pUdpHdr = (PRTNETUDP)pbProtocol;
+ uint16_t UdpChecksum = RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1);
+
+ if (pUdpHdr->uh_sum != UdpChecksum)
+ {
+ pUdpHdr->uh_sum = UdpChecksum;
+ fChecksumAdjusted = true;
+ LogFlow((DEVICE_NAME ":Fixed UDP checksum."));
+ }
+ }
+ }
+
+ if (fChecksumAdjusted)
+ {
+ /*
+ * If we made a copy and the checksum is corrected on the copy,
+ * free the original, return the checksum fixed copy.
+ */
+ if (pFullMsg)
+ {
+ freemsg(pMsg);
+ return pFullMsg;
+ }
+
+ return pMsg;
+ }
+
+ /*
+ * If we made a copy and the checksum is NOT corrected, free the copy,
+ * and return NULL.
+ */
+ if (pFullMsg)
+ freemsg(pFullMsg);
+
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Simple packet dump, used for internal debugging.
+ *
+ * @param pMsg Pointer to the message to analyze and dump.
+ */
+static void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
+
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+ uint8_t *pb = pMsg->b_rptr;
+ if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
+ {
+ PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
+ size_t cbLen = MBLKL(pMsg) - sizeof(*pEthHdr);
+ if (!pMsg->b_cont)
+ {
+ if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
+ LogFlow((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
+ else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
+ LogFlow((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
+ else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
+ {
+ PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
+ if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
+ && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
+ {
+ LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
+ RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
+ }
+ }
+ }
+ else
+ {
+ LogFlow((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
+ }
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
+ {
+ typedef struct VLANHEADER
+ {
+ int Pcp:3;
+ int Cfi:1;
+ int Vid:12;
+ } VLANHEADER;
+
+ VLANHEADER *pVlanHdr = (VLANHEADER *)(pMsg->b_rptr + sizeof(RTNETETHERHDR));
+ LogFlow((DEVICE_NAME ":VLAN Pcp=%d Cfi=%d Id=%d\n", pVlanHdr->Pcp, pVlanHdr->Cfi, pVlanHdr->Vid >> 4));
+ LogFlow((DEVICE_NAME "%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr));
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
+ {
+ PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
+ LogFlow((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
+ {
+ LogFlow((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
+ || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
+ || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
+ {
+ LogFlow((DEVICE_NAME ":IPX packet.\n"));
+ }
+ else
+ {
+ LogFlow((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
+ &pEthHdr->SrcMac));
+ /* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
+ }
+}
+
+
+/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
+bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
+{
+ /*
+ * There is no easy way of obtaining the global host side promiscuous counter.
+ * Currently we just return false.
+ */
+ return false;
+}
+
+
+void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsGetMacAddress pThis=%p\n", pThis));
+ *pMac = pThis->u.s.Mac;
+}
+
+
+bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
+{
+ /*
+ * MAC address change acknowledgements are intercepted on the read side
+ * hence theoritically we are always update to date with any changes.
+ */
+ return pThis->u.s.Mac.au16[0] == pMac->au16[0]
+ && pThis->u.s.Mac.au16[1] == pMac->au16[1]
+ && pThis->u.s.Mac.au16[2] == pMac->au16[2];
+}
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
+
+ /*
+ * Enable/disable promiscuous mode.
+ */
+ vboxnetflt_stream_t *pStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
+ if (pStream)
+ {
+ if (pStream->pReadQueue)
+ {
+ int rc = vboxNetFltSolarisPromiscReq(pStream->pReadQueue, fActive);
+ if (RT_FAILURE(rc))
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive failed to request promiscuous mode! rc=%d\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive queue not found!\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive stream not found!\n"));
+}
+
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
+
+ vboxNetFltSolarisDetachFromInterface(pThis);
+
+ if (pThis->u.s.hFastMtx != NIL_RTSEMFASTMUTEX)
+ {
+ RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
+ pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+ return VINF_SUCCESS;
+}
+
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ /* Nothing to do here. */
+ return VINF_SUCCESS;
+}
+
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
+ /* Nothing to do here. */
+}
+
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p\n"));
+
+ /*
+ * Mutex used for loopback lockouts.
+ */
+ int rc = RTSemFastMutexCreate(&pThis->u.s.hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltSolarisAttachToInterface(pThis);
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisAttachToInterface failed. rc=%Rrc\n", rc));
+ RTSemFastMutexDestroy(pThis->u.s.hFastMtx);
+ pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to create mutex. rc=%Rrc\n", rc));
+
+ return rc;
+}
+
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ /*
+ * Init. the solaris specific data.
+ */
+ pThis->u.s.pvIp4Stream = NULL;
+ pThis->u.s.pvIp6Stream = NULL;
+ pThis->u.s.pvArpStream = NULL;
+ pThis->u.s.pvPromiscStream = NULL;
+ pThis->u.s.hFastMtx = NIL_RTSEMFASTMUTEX;
+ bzero(&pThis->u.s.Mac, sizeof(pThis->u.s.Mac));
+ return VINF_SUCCESS;
+}
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ /*
+ * We don't support interface rediscovery on Solaris hosts because the
+ * filter is very tightly bound to the stream.
+ */
+ return false;
+}
+
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p pSG=%p fDst=%d\n", pThis, pSG, fDst));
+
+ int rc = VINF_SUCCESS;
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+#ifdef VBOXNETFLT_SOLARIS_USE_NETINFO
+ /*
+ * @todo try find a way for IPFilter to accept ethernet frames (currently silently drops them).
+ */
+ mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
+ if (RT_LIKELY(pMsg))
+ {
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+ unsigned uProtocol;
+ if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
+ uProtocol = AF_INET6;
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
+ uProtocol = AF_INET;
+
+ /*
+ * Queue out using netinfo.
+ */
+ netstack_t *pNetStack = netstack_get_current();
+ if (pNetStack)
+ {
+ net_data_t pNetData = net_lookup_impl(NHF_INET, pNetStack);
+ if (pNetData)
+ {
+ phy_if_t pInterface = net_phylookup(pNetData, pThis->szName);
+ if (pInterface)
+ {
+ net_inject_t InjectData;
+ InjectData.ni_packet = pMsg;
+ InjectData.ni_physical = pInterface;
+ bzero(&InjectData.ni_addr, sizeof(InjectData.ni_addr));
+ InjectData.ni_addr.ss_family = uProtocol;
+
+ /*
+ * Queue out rather than direct out transmission.
+ */
+ int rc = net_inject(pNetData, NI_QUEUE_OUT, &InjectData);
+ if (!rc)
+ rc = VINF_SUCCESS;
+ else
+ {
+ LogRel((DEVICE_NAME ":queuing IP packet for transmission failed. rc=%d\n", rc));
+ rc = VERR_NET_IO_ERROR;
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to lookup physical interface.\n"));
+ rc = VERR_NET_IO_ERROR;
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get IP hooks.\n"));
+ rc = VERR_NET_IO_ERROR;
+ }
+ netstack_rele(pNetStack);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit failed to get current net stack.\n"));
+ rc = VERR_NET_IO_ERROR;
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
+ rc = VERR_NO_MEMORY;
+ }
+#else
+ vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvPromiscStream);
+ if (RT_LIKELY(pPromiscStream))
+ {
+ mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
+ if (RT_LIKELY(pMsg))
+ {
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_WIRE\n"));
+
+ vboxNetFltSolarisQueueLoopback(pThis, pPromiscStream, pMsg);
+ putnext(WR(pPromiscStream->Stream.pReadQueue), pMsg);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit vboxNetFltSolarisMBlkFromSG failed.\n"));
+ rc = VERR_NO_MEMORY;
+ }
+ }
+#endif
+ }
+
+ if (fDst & INTNETTRUNKDIR_HOST)
+ {
+ /*
+ * For unplumbed interfaces we would not be bound to IP or ARP.
+ * We either bind to both or neither; so atomic reading one should be sufficient.
+ */
+ vboxnetflt_stream_t *pIp4Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp4Stream);
+ if (!pIp4Stream)
+ return rc;
+
+ /*
+ * Create a message block and send it up the host stack (upstream).
+ */
+ mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
+ if (RT_LIKELY(pMsg))
+ {
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+
+ /*
+ * Send message up ARP stream.
+ */
+ if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
+ {
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST ARP\n"));
+
+ vboxnetflt_stream_t *pArpStream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvArpStream);
+ if (pArpStream)
+ {
+ /*
+ * Construct a DL_UNITDATA_IND style message for ARP as it doesn't understand fast path.
+ */
+ mblk_t *pDlpiMsg;
+ int rc = vboxNetFltSolarisRawToUnitData(pMsg, &pDlpiMsg);
+ if (RT_SUCCESS(rc))
+ {
+ pMsg = pDlpiMsg;
+
+ queue_t *pArpReadQueue = pArpStream->pReadQueue;
+ putnext(pArpReadQueue, pMsg);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisRawToUnitData failed!\n"));
+ freemsg(pMsg);
+ rc = VERR_NO_MEMORY;
+ }
+ }
+ else
+ freemsg(pMsg); /* Should really never happen... */
+ }
+ else
+ {
+ vboxnetflt_stream_t *pIp6Stream = ASMAtomicUoReadPtr((void * volatile *)&pThis->u.s.pvIp6Stream);
+ if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6)
+ && pIp6Stream)
+ {
+ /*
+ * Send messages up IPv6 stream.
+ */
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv6\n"));
+
+ pMsg->b_rptr += sizeof(RTNETETHERHDR);
+ queue_t *pIp6ReadQueue = pIp6Stream->pReadQueue;
+ putnext(pIp6ReadQueue, pMsg);
+ }
+ else
+ {
+ /*
+ * Send messages up IPv4 stream.
+ */
+ LogFlow((DEVICE_NAME ":vboxNetFltPortOsXmit INTNETTRUNKDIR_HOST IPv4\n"));
+
+ pMsg->b_rptr += sizeof(RTNETETHERHDR);
+ queue_t *pIp4ReadQueue = pIp4Stream->pReadQueue;
+ putnext(pIp4ReadQueue, pMsg);
+ }
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed.\n"));
+ rc = VERR_NO_MEMORY;
+ }
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/solaris/vboxflt.conf b/src/VBox/HostDrivers/VBoxNetFlt/solaris/vboxflt.conf
new file mode 100644
index 000000000..f00841d3e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/solaris/vboxflt.conf
@@ -0,0 +1,25 @@
+#
+# Sun xVM VirtualBox
+# Solaris Host VBoxFlt Configuration
+#
+# Copyright (C) 2008 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+# This needs to go into /platform/i86pc/kernel/drv,
+# while the 64-bit driver object goes into the amd64
+# subdirectory (32-bit drivers goes into the same
+# directory).
+#
+name="vboxflt" parent="pseudo" instance=0;
diff --git a/src/VBox/HostDrivers/VBoxTAP/Makefile.kmk b/src/VBox/HostDrivers/VBoxTAP/Makefile.kmk
new file mode 100644
index 000000000..6b4f99a60
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/Makefile.kmk
@@ -0,0 +1,83 @@
+# $Id: Makefile.kmk 12252 2008-09-09 01:58:29Z vboxsync $
+## @file
+# Sub-Makefile for the Windows Network Driver.
+#
+
+#
+# Copyright (C) 2006-2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+
+#
+# VBoxTap
+#
+SYSMODS.win += VBoxTAP
+VBoxTAP_TEMPLATE = VBOXR0DRV
+ifdef VBOX_SIGNING_MODE
+ VBoxTAP_NOINST = true
+endif
+VBoxTAP_SDKS = W2K3DDK WINPSDKINCS
+VBoxTAP_LDFLAGS.x86 = -Entry:DriverEntry@8
+VBoxTAP_LDFLAGS.amd64 = -Entry:DriverEntry
+VBoxTAP_SOURCES = \
+ tapdrvr.c \
+ VBoxTAP.rc
+VBoxTAP_LIBS = \
+ $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB) \
+ $(PATH_SDK_W2K3DDK_LIB)/ntoskrnl.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/hal.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/ndis.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/ntstrsafe.lib \
+ $(PATH_SDK_W2K3DDK_LIB)/BufferOverflowK.lib
+
+
+#
+# Install the .inf.
+#
+INSTALLS.win += VBoxTAP-inf
+VBoxTAP-inf_INST = $(INST_BIN)
+VBoxTAP-inf_MODE = a+r,u+w
+VBoxTAP-inf_SOURCES = \
+ $(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.inf
+VBoxTAP-inf_CLEAN = $(VBoxTAP-inf_SOURCES)
+VBoxTAP-inf_BLDDIRS = $(PATH_TARGET)/VBoxTAPCat.dir
+
+$(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.inf: $(PATH_SUB_CURRENT)/VBoxTAP.inf $(MAKEFILE_CURRENT) | $$(call DIRDEP,$$(@D))
+ $(call MSG_GENERATE,VBoxTAP-inf,$@,$<)
+ $(call VBOX_EDIT_INF_FN,$<,$@)
+
+ifdef VBOX_SIGNING_MODE
+VBoxTAP-inf_SOURCES += \
+ $(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.cat \
+ $(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.sys
+
+$(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.sys: $$(TARGET_VBoxTAP) | $$(call DIRDEP,$$(@D))
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.cat: \
+ $(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.inf \
+ $(PATH_TARGET)/VBoxTAPCat.dir/VBoxTAP.sys
+ $(call MSG_TOOL,Inf2Cat,VBoxTAP-inf,$@,$<)
+ $(INSTALL) -m 644 $(TARGET_VBoxTAP) $(@D)
+ $(call VBOX_MAKE_CAT_FN, $(@D),$@)
+endif # signing
+
+
+# generate rules
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/VBox/HostDrivers/VBoxTAP/VBoxTAP.inf b/src/VBox/HostDrivers/VBoxTAP/VBoxTAP.inf
new file mode 100644
index 000000000..4dd5c25f1
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/VBoxTAP.inf
@@ -0,0 +1,164 @@
+;
+; VirtualBox Host Interface Networking Driver
+;
+;
+; Copyright (C) 2006-2007 Sun Microsystems, Inc.
+;
+; 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.
+;
+; Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+; Clara, CA 95054 USA or visit http://www.sun.com if you need
+; additional information or have any questions.
+;
+
+[Version]
+ Signature = "$Windows NT$"
+;cat CatalogFile = VBoxTAP.cat
+ ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+ Provider = %Provider%
+ Class = Net
+
+; This version number should match the version
+; number given in SOURCES.
+;; @todo: edit this too? what's the above comment about?
+ DriverVer=02/19/2007,8.00.00.0005
+
+[Strings]
+; Note; there are hardcoded checks for these strings!!
+ DeviceDescription = "VirtualBox TAP Adapter"
+ Provider = "Sun Microsystems, Inc."
+
+;----------------------------------------------------------------
+; Manufacturer + Product Section (Done)
+;----------------------------------------------------------------
+[Manufacturer]
+;x86 %Provider% = VBoxTAP
+;amd64 %Provider% = VBoxTAP, NTamd64
+
+;x86 [VBoxTAP]
+;amd64 [VBoxTAP.NTamd64]
+ %DeviceDescription% = VBoxTAP.ndi, VBoxTAP
+
+;---------------------------------------------------------------
+; Driver Section (Done)
+;---------------------------------------------------------------
+
+;----------------- Characteristics ------------
+; NCF_PHYSICAL = 0x04
+; NCF_VIRTUAL = 0x01
+; NCF_SOFTWARE_ENUMERATED = 0x02
+; NCF_HIDDEN = 0x08
+; NCF_NO_SERVICE = 0x10
+; NCF_HAS_UI = 0x80
+;----------------- Characteristics ------------
+
+[VBoxTAP.ndi]
+ CopyFiles = VBoxTAP.driver, VBoxTAP.files
+ AddReg = VBoxTAP.reg
+ AddReg = VBoxTAP.params.reg
+ Characteristics = 0x81 ; NCF_PHYSICAL | NCF_HAS_UI
+ BusType = 1
+
+[VBoxTAP.ndi.Services]
+ AddService = VBoxTAP, 2, VBoxTAP.service
+
+[VBoxTAP.reg]
+ HKR, Ndi, Service, 0, "VBoxTAP"
+ HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+ HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+ HKR, , Manufacturer, 0, "%Provider%"
+ HKR, , ProductName, 0, "%DeviceDescription%"
+
+[VBoxTAP.params.reg]
+ HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+ HKR, Ndi\params\MTU, Type, 0, "int"
+ HKR, Ndi\params\MTU, Default, 0, "1500"
+ HKR, Ndi\params\MTU, Optional, 0, "0"
+ HKR, Ndi\params\MTU, Min, 0, "100"
+ HKR, Ndi\params\MTU, Max, 0, "16384"
+ HKR, Ndi\params\MTU, Step, 0, "1"
+ HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
+ HKR, Ndi\params\MediaStatus, Type, 0, "enum"
+ HKR, Ndi\params\MediaStatus, Default, 0, "0"
+ HKR, Ndi\params\MediaStatus, Optional, 0, "0"
+ HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
+ HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
+ HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
+ HKR, Ndi\params\MAC, Type, 0, "edit"
+ HKR, Ndi\params\MAC, Optional, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access"
+ HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum"
+ HKR, Ndi\params\AllowNonAdmin, Default, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0"
+ HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed"
+ HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed"
+
+
+;----------------------------------------------------------------
+; Service Section
+;----------------------------------------------------------------
+
+;---------- Service Type -------------
+; SERVICE_KERNEL_DRIVER = 0x01
+; SERVICE_WIN32_OWN_PROCESS = 0x10
+;---------- Service Type -------------
+
+;---------- Start Mode ---------------
+; SERVICE_BOOT_START = 0x0
+; SERVICE_SYSTEM_START = 0x1
+; SERVICE_AUTO_START = 0x2
+; SERVICE_DEMAND_START = 0x3
+; SERVICE_DISABLED = 0x4
+;---------- Start Mode ---------------
+
+[VBoxTAP.service]
+ DisplayName = %DeviceDescription%
+ ServiceType = 1
+ StartType = 3
+ ErrorControl = 1
+ LoadOrderGroup = NDIS
+ ServiceBinary = %12%\VBoxTAP.sys
+
+;-----------------------------------------------------------------
+; File Installation
+;-----------------------------------------------------------------
+
+;----------------- Copy Flags ------------
+; COPYFLG_NOSKIP = 0x02
+; COPYFLG_NOVERSIONCHECK = 0x04
+;----------------- Copy Flags ------------
+
+; SourceDisksNames
+; diskid = description[, [tagfile] [, <unused>, subdir]]
+; 1 = "Intel Driver Disk 1",e100bex.sys,,
+
+[SourceDisksNames]
+ 1 = %DeviceDescription%, VBoxTAP.sys
+
+; SourceDisksFiles
+; filename_on_source = diskID[, [subdir][, size]]
+; e100bex.sys = 1,, ; on distribution disk 1
+
+[SourceDisksFiles]
+VBoxTAP.sys = 1
+
+[DestinationDirs]
+ VBoxTAP.files = 11
+ VBoxTAP.driver = 12
+
+[VBoxTAP.files]
+; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
+[VBoxTAP.driver]
+ VBoxTAP.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
+;---------------------------------------------------------------
+; End
+;---------------------------------------------------------------
diff --git a/src/VBox/HostDrivers/VBoxTAP/common.h b/src/VBox/HostDrivers/VBoxTAP/common.h
new file mode 100644
index 000000000..d782043c3
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/common.h
@@ -0,0 +1,77 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//===============================================
+// This file is included both by OpenVPN and
+// the TAP-Win32 driver and contains definitions
+// common to both.
+//===============================================
+
+//=============
+// TAP IOCTLs
+//=============
+
+#ifndef VBOX
+#define TAP_CONTROL_CODE(request,method) \
+ CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
+
+#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
+#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
+#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
+#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
+#endif
+
+//=================
+// Registry keys
+//=================
+
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+//======================
+// Filesystem prefixes
+//======================
+
+#define USERMODEDEVICEDIR "\\\\.\\Global\\"
+#define SYSDEVICEDIR "\\Device\\"
+#define USERDEVICEDIR "\\DosDevices\\Global\\"
+#define TAPSUFFIX ".tap"
+
+//=========================================================
+// TAP_COMPONENT_ID -- This string defines the TAP driver
+// type -- different component IDs can reside in the system
+// simultaneously.
+//=========================================================
+
+#define TAP_COMPONENT_ID "VBoxTAP"
diff --git a/src/VBox/HostDrivers/VBoxTAP/config-win32.h b/src/VBox/HostDrivers/VBoxTAP/config-win32.h
new file mode 100644
index 000000000..1c9eb77cf
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/config-win32.h
@@ -0,0 +1,309 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Configuration header for Win32 using the mingw environment.
+ * Manually edited based on linux version as generated by autoconf.
+ *
+ * config-win32.h is normally generated by copying
+ * config-win32.h.in -> config-win32.h and replacing
+ * [ampersand] VERSION [ampersand]
+ * with the appropriate version #. This is normally
+ * done automatically by configure.ac
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+
+#define sleep(x) Sleep((x)*1000)
+
+#define random rand
+#define srandom srand
+
+typedef unsigned long in_addr_t;
+
+#ifndef _SSIZE_T_
+#define _SSIZE_T_
+ typedef unsigned int ssize_t;
+#endif
+
+/* Append a label to program startup title */
+//#define DEBUG_LABEL "DEBUG1"
+
+/* Should we print debug info from driver? */
+//#define TAP_WIN32_DEBUG
+
+/*
+ * Minimum TAP-Win32 version number expected by userspace
+ *
+ * The TAP-Win32 version number is defined in tap-win32/SOURCES
+ */
+#define TAP_WIN32_MIN_MAJOR 8
+#define TAP_WIN32_MIN_MINOR 4
+
+/* Allow --askpass and --auth-user-pass passwords to be read from a file */
+/* #undef ENABLE_PASSWORD_SAVE */
+
+/* Enable client/server capability */
+#define ENABLE_CLIENT_SERVER 1
+
+/* Enable client capability only */
+/* #undef ENABLE_CLIENT_ONLY */
+
+/* Enable management server capability */
+#define ENABLE_MANAGEMENT 1
+
+/* Enable HTTP proxy support */
+#define ENABLE_HTTP_PROXY 1
+
+/* Enable Socks proxy support */
+#define ENABLE_SOCKS 1
+
+/* Enable internal fragmentation support */
+#define ENABLE_FRAGMENT 1
+
+/* Enable smaller executable size */
+/* #undef ENABLE_SMALL */
+
+/* Enable debugging support */
+#define ENABLE_DEBUG 1
+
+/* if defined, will allow usage of the --plugin directive */
+#define USE_LOAD_LIBRARY
+
+/* Dimension size to use for empty array declaration */
+#define EMPTY_ARRAY_SIZE 0
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the `ENGINE_register_all_complete' function. */
+#define HAVE_ENGINE_REGISTER_ALL_COMPLETE 1
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+#define HAVE_ENGINE_CLEANUP 1
+
+/* gettimeofday() is implemented in otime.c for Windows */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the 'chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `chdir' function. */
+#define HAVE_CHDIR 1
+
+/* Define to 1 if your compiler supports GNU GCC-style variadic macros */
+#ifndef _MSC_VER /* Defines MSFT compiler version. Defined as 1200 for MSVC++ 6.0. */
+#define HAVE_CPP_VARARG_MACRO_GCC 1
+#endif
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#define HAVE_CTYPE_H 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `EVP_CIPHER_CTX_set_key_length' function. */
+#define HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getsockopt' function. */
+#define HAVE_GETSOCKOPT 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `setsockopt' function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_STDINT_H 1
+#endif
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `system' function. */
+#define HAVE_SYSTEM 1
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_SYS_FILE_H 1
+#endif
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_SYS_TIME_H 1
+#endif
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `time' function. */
+#define HAVE_TIME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Special Windows version of getpass() defined in io.c */
+#define HAVE_GETPASS 1
+
+/* Name of package */
+#define PACKAGE "openvpn"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "openvpn-users@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "OpenVPN"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "openvpn"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@VERSION@" /* AUTO_VERSION */
+
+/* Define to the full name and version of this package. */
+#ifdef DEBUG_LABEL
+#define PACKAGE_STRING "OpenVPN " PACKAGE_VERSION " " DEBUG_LABEL
+#else
+#define PACKAGE_STRING "OpenVPN " PACKAGE_VERSION
+#endif
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of a `unsigned int', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_INT 4
+
+/* The size of a `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* A string representing our target */
+#ifdef _MSC_VER
+#define TARGET_ALIAS "Win32-MSVC++"
+#else
+#define TARGET_ALIAS "Win32-MinGW"
+#endif
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#ifndef _MSC_VER
+#define TIME_WITH_SYS_TIME 1
+#endif
+
+/* Use OpenSSL crypto library */
+#define USE_CRYPTO 1
+
+/* Use LZO compression library */
+#define USE_LZO 1
+
+/* Use OpenSSL SSL library */
+#define USE_SSL 1
+
+/* Version number of package */
+#define VERSION PACKAGE_VERSION
+
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+ if it is not supported. */
+#define inline __inline
+
+/* type to use in place of socklen_t if not defined */
+#define socklen_t unsigned int
+
+/* 32-bit unsigned type */
+#define uint32_t unsigned int
+
+/* 16-bit unsigned type */
+#define uint16_t unsigned short
+
+/* 8-bit unsigned type */
+#define uint8_t unsigned char
+
+/* Route command */
+#define ROUTE_PATH "route"
+
+/* Windows doesn't support PTHREAD yet */
+#ifdef USE_PTHREAD
+#error The Windows version of OpenVPN does not support PTHREAD yet
+#endif
+
+#ifdef _MSC_VER
+/* MSVC++ hacks */
+#include <io.h>
+#include <direct.h>
+#define vsnprintf _vsnprintf
+#define vsnwprintf _vsnwprintf
+#define snwprintf _snwprintf
+#define write _write
+#define open _open
+#define read _read
+#define close _close
+#define chdir _chdir
+#define S_IRUSR 0
+#define S_IWUSR 0
+typedef int intptr_t;
+#undef S_NORMAL
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/constants.h b/src/VBox/HostDrivers/VBoxTAP/constants.h
new file mode 100644
index 000000000..a014971ca
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/constants.h
@@ -0,0 +1,55 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//====================================================================
+// Product and Version public settings
+//====================================================================
+
+#define PRODUCT_STRING "VirtualBox TAP Adapter"
+
+#define TAP_NDIS_MAJOR_VERSION 5
+#define TAP_NDIS_MINOR_VERSION 0
+
+//===========================================================
+// Driver constants
+//===========================================================
+
+#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER))
+#define ETHERNET_MTU 1500
+#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE)
+#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE)
+
+#define NIC_MAX_MCAST_LIST 32 // Max length of multicast address list
+
+#define MINIMUM_MTU 576 // USE TCP Minimum MTU
+#define MAXIMUM_MTU 65536 // IP maximum MTU
+
+#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size
+#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace
+
+#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions
diff --git a/src/VBox/HostDrivers/VBoxTAP/dhcp.c b/src/VBox/HostDrivers/VBoxTAP/dhcp.c
new file mode 100644
index 000000000..5b8eea6eb
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/dhcp.c
@@ -0,0 +1,603 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//=========================
+// Code to set DHCP options
+//=========================
+
+VOID
+SetDHCPOpt (DHCPMsg *m, void *data, unsigned int len)
+{
+ if (!m->overflow)
+ {
+ if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE)
+ {
+ if (len)
+ {
+ NdisMoveMemory (m->msg.options + m->optlen, data, len);
+ m->optlen += len;
+ }
+ }
+ else
+ {
+ m->overflow = TRUE;
+ }
+ }
+}
+
+VOID
+SetDHCPOpt0 (DHCPMsg *msg, int type)
+{
+ DHCPOPT0 opt;
+ opt.type = (UCHAR) type;
+ SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt8 (DHCPMsg *msg, int type, ULONG data)
+{
+ DHCPOPT8 opt;
+ opt.type = (UCHAR) type;
+ opt.len = sizeof (opt.data);
+ opt.data = (UCHAR) data;
+ SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt32 (DHCPMsg *msg, int type, ULONG data)
+{
+ DHCPOPT32 opt;
+ opt.type = (UCHAR) type;
+ opt.len = sizeof (opt.data);
+ opt.data = data;
+ SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+//==============
+// Checksum code
+//==============
+
+USHORT
+ip_checksum (const UCHAR *buf, const int len_ip_header)
+{
+ USHORT word16;
+ ULONG sum = 0;
+ int i;
+
+ // make 16 bit words out of every two adjacent 8 bit words in the packet
+ // and add them up
+ for (i = 0; i < len_ip_header - 1; i += 2) {
+ word16 = ((buf[i] << 8) & 0xFF00) + (buf[i+1] & 0xFF);
+ sum += (ULONG) word16;
+ }
+
+ // take only 16 bits out of the 32 bit sum and add up the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // one's complement the result
+ return ((USHORT) ~sum);
+}
+
+USHORT
+udp_checksum (const UCHAR *buf,
+ const int len_udp,
+ const UCHAR *src_addr,
+ const UCHAR *dest_addr)
+{
+ USHORT word16;
+ ULONG sum = 0;
+ int i;
+
+ // make 16 bit words out of every two adjacent 8 bit words and
+ // calculate the sum of all 16 bit words
+ for (i = 0; i < len_udp; i += 2){
+ word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
+ sum += word16;
+ }
+
+ // add the UDP pseudo header which contains the IP source and destination addresses
+ for (i = 0; i < 4; i += 2){
+ word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
+ sum += word16;
+ }
+ for (i = 0; i < 4; i += 2){
+ word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ // the protocol number and the length of the UDP packet
+ sum += (USHORT) IPPROTO_UDP + (USHORT) len_udp;
+
+ // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // Take the one's complement of sum
+ return ((USHORT) ~sum);
+}
+
+//================================
+// Set IP and UDP packet checksums
+//================================
+
+VOID
+SetChecksumDHCPMsg (DHCPMsg *m)
+{
+ // Set IP checksum
+ m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR)));
+
+ // Set UDP Checksum
+ m->msg.pre.udp.check = htons (udp_checksum ((UCHAR *) &m->msg.pre.udp,
+ sizeof (UDPHDR) + sizeof (DHCP) + m->optlen,
+ (UCHAR *)&m->msg.pre.ip.saddr,
+ (UCHAR *)&m->msg.pre.ip.daddr));
+}
+
+//===================
+// DHCP message tests
+//===================
+
+int
+GetDHCPMessageType (const DHCP *dhcp, const int optlen)
+{
+ const UCHAR *p = (UCHAR *) (dhcp + 1);
+ int i;
+
+ for (i = 0; i < optlen; ++i)
+ {
+ const UCHAR type = p[i];
+ const int room = optlen - i - 1;
+ if (type == DHCP_END) // didn't find what we were looking for
+ return -1;
+ else if (type == DHCP_PAD) // no-operation
+ ;
+ else if (type == DHCP_MSG_TYPE) // what we are looking for
+ {
+ if (room >= 2)
+ {
+ if (p[i+1] == 1) // message length should be 1
+ return p[i+2]; // return message type
+ }
+ return -1;
+ }
+ else // some other message
+ {
+ if (room >= 1)
+ {
+ const int len = p[i+1]; // get message length
+ i += (len + 1); // advance to next message
+ }
+ }
+ }
+ return -1;
+}
+
+BOOLEAN
+DHCPMessageOurs (const TapAdapterPointer p_Adapter,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp)
+{
+ // Must be UDPv4 protocol
+ if (!(eth->proto == htons (ETH_P_IP) && ip->protocol == IPPROTO_UDP))
+ return FALSE;
+
+ // Source MAC must be our adapter
+ if (!MAC_EQUAL (eth->src, p_Adapter->m_MAC))
+ return FALSE;
+
+ // Dest MAC must be either broadcast or our virtual DHCP server
+ if (!(MAC_EQUAL (eth->dest, p_Adapter->m_MAC_Broadcast)
+ || MAC_EQUAL (eth->dest, p_Adapter->m_dhcp_server_mac)))
+ return FALSE;
+
+ // Port numbers must be correct
+ if (!(udp->dest == htons (BOOTPS_PORT)
+ && udp->source == htons (BOOTPC_PORT)))
+ return FALSE;
+
+ // Hardware address must be MAC addr sized
+ if (!(dhcp->hlen == sizeof (MACADDR)))
+ return FALSE;
+
+ // Hardware address must match our adapter
+ if (!MAC_EQUAL (eth->src, dhcp->chaddr))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+//=====================================================
+// Build all of DHCP packet except for DHCP options.
+// Assume that *p has been zeroed before we are called.
+//=====================================================
+
+VOID
+BuildDHCPPre (const TapAdapterPointer a,
+ DHCPPre *p,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ const int optlen,
+ const int type)
+{
+ // Should we broadcast or direct to a specific MAC / IP address?
+ const BOOLEAN broadcast = (type == DHCPNAK
+ || MAC_EQUAL (eth->dest, a->m_MAC_Broadcast));
+ // Build ethernet header
+
+ COPY_MAC (p->eth.src, a->m_dhcp_server_mac);
+
+ if (broadcast)
+ COPY_MAC (p->eth.dest, a->m_MAC_Broadcast);
+ else
+ COPY_MAC (p->eth.dest, eth->src);
+
+ p->eth.proto = htons (ETH_P_IP);
+
+ // Build IP header
+
+ p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2);
+ p->ip.tos = 0;
+ p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen);
+ p->ip.id = 0;
+ p->ip.frag_off = 0;
+ p->ip.ttl = 16;
+ p->ip.protocol = IPPROTO_UDP;
+ p->ip.check = 0;
+ p->ip.saddr = a->m_dhcp_server_ip;
+
+ if (broadcast)
+ p->ip.daddr = ~0;
+ else
+ p->ip.daddr = a->m_dhcp_addr;
+
+ // Build UDP header
+
+ p->udp.source = htons (BOOTPS_PORT);
+ p->udp.dest = htons (BOOTPC_PORT);
+ p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen);
+ p->udp.check = 0;
+
+ // Build DHCP response
+
+ p->dhcp.op = BOOTREPLY;
+ p->dhcp.htype = 1;
+ p->dhcp.hlen = sizeof (MACADDR);
+ p->dhcp.hops = 0;
+ p->dhcp.xid = dhcp->xid;
+ p->dhcp.secs = 0;
+ p->dhcp.flags = 0;
+ p->dhcp.ciaddr = 0;
+
+ if (type == DHCPNAK)
+ p->dhcp.yiaddr = 0;
+ else
+ p->dhcp.yiaddr = a->m_dhcp_addr;
+
+ p->dhcp.siaddr = a->m_dhcp_server_ip;
+ p->dhcp.giaddr = 0;
+ COPY_MAC (p->dhcp.chaddr, eth->src);
+ p->dhcp.magic = htonl (0x63825363);
+}
+//=============================
+// Build specific DHCP messages
+//=============================
+
+VOID
+SendDHCPMsg (const TapAdapterPointer a,
+ const int type,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp)
+{
+ DHCPMsg *pkt;
+
+ if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK))
+ {
+ DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type));
+ return;
+ }
+
+ pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE);
+
+ if (pkt)
+ {
+ //-----------------------
+ // Build DHCP options
+ //-----------------------
+
+ // Message Type
+ SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type);
+
+ // Server ID
+ SetDHCPOpt32 (pkt, DHCP_SERVER_ID, a->m_dhcp_server_ip);
+
+ if (type == DHCPOFFER || type == DHCPACK)
+ {
+ // Lease Time
+ SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (a->m_dhcp_lease_time));
+
+ // Netmask
+ SetDHCPOpt32 (pkt, DHCP_NETMASK, a->m_dhcp_netmask);
+
+ // Other user-defined options
+ SetDHCPOpt (pkt,
+ a->m_dhcp_user_supplied_options_buffer,
+ a->m_dhcp_user_supplied_options_buffer_len);
+ }
+
+ // End
+ SetDHCPOpt0 (pkt, DHCP_END);
+
+ if (!DHCPMSG_OVERFLOW (pkt))
+ {
+ // The initial part of the DHCP message (not including options) gets built here
+ BuildDHCPPre (a,
+ &pkt->msg.pre,
+ eth,
+ ip,
+ udp,
+ dhcp,
+ DHCPMSG_LEN_OPT (pkt),
+ type);
+
+ SetChecksumDHCPMsg (pkt);
+
+ DUMP_PACKET ("DHCPMsg",
+ DHCPMSG_BUF (pkt),
+ DHCPMSG_LEN_FULL (pkt));
+
+ // Return DHCP response to kernel
+ InjectPacket (a,
+ DHCPMSG_BUF (pkt),
+ DHCPMSG_LEN_FULL (pkt));
+ }
+ else
+ {
+ DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n"));
+ }
+
+ MemFree (pkt, sizeof (DHCPMsg));
+ }
+}
+
+//===================================================================
+// Handle a BOOTPS packet produced by the local system to
+// resolve the address/netmask of this adapter.
+// If we are in TAP_IOCTL_CONFIG_DHCP_MASQ mode, reply
+// to the message. Return TRUE if we processed the passed
+// message, so that downstream stages can ignore it.
+//===================================================================
+
+BOOLEAN
+ProcessDHCP (TapAdapterPointer p_Adapter,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ int optlen)
+{
+ int msg_type;
+
+ // Sanity check IP header
+ if (!(ntohs (ip->tot_len) == sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen
+ && (ntohs (ip->frag_off) & IP_OFFMASK) == 0))
+ return TRUE;
+
+ // Does this message belong to us?
+ if (!DHCPMessageOurs (p_Adapter, eth, ip, udp, dhcp))
+ return FALSE;
+
+ msg_type = GetDHCPMessageType (dhcp, optlen);
+
+ // Drop non-BOOTREQUEST messages
+ if (dhcp->op != BOOTREQUEST)
+ return TRUE;
+
+ // Drop any messages except DHCPDISCOVER or DHCPREQUEST
+ if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST))
+ return TRUE;
+
+ // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK?
+ if (msg_type == DHCPREQUEST
+ && ((dhcp->ciaddr && dhcp->ciaddr != p_Adapter->m_dhcp_addr)
+ || !p_Adapter->m_dhcp_received_discover
+ || p_Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD))
+ SendDHCPMsg (p_Adapter,
+ DHCPNAK,
+ eth, ip, udp, dhcp);
+ else
+ SendDHCPMsg (p_Adapter,
+ (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK),
+ eth, ip, udp, dhcp);
+
+ // Remember if we received a DHCPDISCOVER
+ if (msg_type == DHCPDISCOVER)
+ p_Adapter->m_dhcp_received_discover = TRUE;
+
+ // Is this a bad DHCPREQUEST?
+ if (msg_type == DHCPREQUEST && dhcp->ciaddr != p_Adapter->m_dhcp_addr)
+ ++p_Adapter->m_dhcp_bad_requests;
+
+ return TRUE;
+}
+
+#if DBG
+
+const char *
+message_op_text (int op)
+{
+ switch (op)
+ {
+ case BOOTREQUEST:
+ return "BOOTREQUEST";
+ case BOOTREPLY:
+ return "BOOTREPLY";
+ default:
+ return "???";
+ }
+}
+
+const char *
+message_type_text (int type)
+{
+ switch (type)
+ {
+ case DHCPDISCOVER:
+ return "DHCPDISCOVER";
+ case DHCPOFFER:
+ return "DHCPOFFER";
+ case DHCPREQUEST:
+ return "DHCPREQUEST";
+ case DHCPDECLINE:
+ return "DHCPDECLINE";
+ case DHCPACK:
+ return "DHCPACK";
+ case DHCPNAK:
+ return "DHCPNAK";
+ case DHCPRELEASE:
+ return "DHCPRELEASE";
+ case DHCPINFORM:
+ return "DHCPINFORM";
+ default:
+ return "???";
+ }
+}
+
+const char *
+port_name (int port)
+{
+ switch (port)
+ {
+ case BOOTPS_PORT:
+ return "BOOTPS";
+ case BOOTPC_PORT:
+ return "BOOTPC";
+ default:
+ return "unknown";
+ }
+}
+
+VOID
+DumpDHCP (const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ const int optlen)
+{
+ DEBUGP ((" %s", message_op_text (dhcp->op)));
+ DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen))));
+ PrIP (ip->saddr);
+ DEBUGP ((":%s[", port_name (ntohs (udp->source))));
+ PrMac (eth->src);
+ DEBUGP (("] -> "));
+ PrIP (ip->daddr);
+ DEBUGP ((":%s[", port_name (ntohs (udp->dest))));
+ PrMac (eth->dest);
+ DEBUGP (("]"));
+ if (dhcp->ciaddr)
+ {
+ DEBUGP ((" ci="));
+ PrIP (dhcp->ciaddr);
+ }
+ if (dhcp->yiaddr)
+ {
+ DEBUGP ((" yi="));
+ PrIP (dhcp->yiaddr);
+ }
+ if (dhcp->siaddr)
+ {
+ DEBUGP ((" si="));
+ PrIP (dhcp->siaddr);
+ }
+ if (dhcp->hlen == sizeof (MACADDR))
+ {
+ DEBUGP ((" ch="));
+ PrMac (dhcp->chaddr);
+ }
+
+ DEBUGP ((" xid=0x%08x", ntohl (dhcp->xid)));
+
+ if (ntohl (dhcp->magic) != 0x63825363)
+ DEBUGP ((" ma=0x%08x", ntohl (dhcp->magic)));
+ if (dhcp->htype != 1)
+ DEBUGP ((" htype=%d", dhcp->htype));
+ if (dhcp->hops)
+ DEBUGP ((" hops=%d", dhcp->hops));
+ if (ntohs (dhcp->secs))
+ DEBUGP ((" secs=%d", ntohs (dhcp->secs)));
+ if (ntohs (dhcp->flags))
+ DEBUGP ((" flags=0x%04x", ntohs (dhcp->flags)));
+
+ // extra stuff
+
+ if (ip->version_len != 0x45)
+ DEBUGP ((" vl=0x%02x", ip->version_len));
+ if (ntohs (ip->tot_len) != sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen)
+ DEBUGP ((" tl=%d", ntohs (ip->tot_len)));
+ if (ntohs (udp->len) != sizeof (UDPHDR) + sizeof (DHCP) + optlen)
+ DEBUGP ((" ul=%d", ntohs (udp->len)));
+
+ if (ip->tos)
+ DEBUGP ((" tos=0x%02x", ip->tos));
+ if (ntohs (ip->id))
+ DEBUGP ((" id=0x%04x", ntohs (ip->id)));
+ if (ntohs (ip->frag_off))
+ DEBUGP ((" frag_off=0x%04x", ntohs (ip->frag_off)));
+
+ DEBUGP ((" ttl=%d", ip->ttl));
+ DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip->check),
+ ip_checksum ((UCHAR*)ip, sizeof (IPHDR))));
+ DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp->check),
+ udp_checksum ((UCHAR *) udp,
+ sizeof (UDPHDR) + sizeof (DHCP) + optlen,
+ (UCHAR *) &ip->saddr,
+ (UCHAR *) &ip->daddr),
+ optlen));
+
+ // Options
+ {
+ const UCHAR *opt = (UCHAR *) (dhcp + 1);
+ int i;
+
+ DEBUGP ((" OPT"));
+ for (i = 0; i < optlen; ++i)
+ {
+ const UCHAR data = opt[i];
+ DEBUGP ((".%d", data));
+ }
+ }
+}
+
+#endif /* DEBUG */
diff --git a/src/VBox/HostDrivers/VBoxTAP/dhcp.h b/src/VBox/HostDrivers/VBoxTAP/dhcp.h
new file mode 100644
index 000000000..f99973080
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/dhcp.h
@@ -0,0 +1,168 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#pragma pack(1)
+
+//===================================================
+// How many bad DHCPREQUESTs do we receive before we
+// return a NAK?
+//
+// A bad DHCPREQUEST is defined to be one where the
+// requestor doesn't know its IP address.
+//===================================================
+
+#define BAD_DHCPREQUEST_NAK_THRESHOLD 3
+
+//==============================================
+// Maximum number of DHCP options bytes supplied
+//==============================================
+
+#define DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE 256
+#define DHCP_OPTIONS_BUFFER_SIZE 256
+
+//===================================
+// UDP port numbers of DHCP messages.
+//===================================
+
+#define BOOTPS_PORT 67
+#define BOOTPC_PORT 68
+
+//===========================
+// The DHCP message structure
+//===========================
+
+typedef struct {
+# define BOOTREQUEST 1
+# define BOOTREPLY 2
+ UCHAR op; /* message op */
+
+ UCHAR htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */
+ UCHAR hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */
+ UCHAR hops; /* client sets to 0, may be used by relay agents */
+ ULONG xid; /* transaction ID, chosen by client */
+ USHORT secs; /* seconds since request process began, set by client */
+ USHORT flags;
+ ULONG ciaddr; /* client IP address, client sets if known */
+ ULONG yiaddr; /* 'your' IP address -- server's response to client */
+ ULONG siaddr; /* server IP address */
+ ULONG giaddr; /* relay agent IP address */
+ UCHAR chaddr[16]; /* client hardware address */
+ UCHAR sname[64]; /* optional server host name */
+ UCHAR file[128]; /* boot file name */
+ ULONG magic; /* must be 0x63825363 (network order) */
+} DHCP;
+
+typedef struct {
+ ETH_HEADER eth;
+ IPHDR ip;
+ UDPHDR udp;
+ DHCP dhcp;
+} DHCPPre;
+
+typedef struct {
+ DHCPPre pre;
+ UCHAR options[DHCP_OPTIONS_BUFFER_SIZE];
+} DHCPFull;
+
+typedef struct {
+ unsigned int optlen;
+ BOOLEAN overflow;
+ DHCPFull msg;
+} DHCPMsg;
+
+//===================
+// Macros for DHCPMSG
+//===================
+
+#define DHCPMSG_LEN_BASE(p) (sizeof (DHCPPre))
+#define DHCPMSG_LEN_OPT(p) ((p)->optlen)
+#define DHCPMSG_LEN_FULL(p) (DHCPMSG_LEN_BASE(p) + DHCPMSG_LEN_OPT(p))
+#define DHCPMSG_BUF(p) ((UCHAR*) &(p)->msg)
+#define DHCPMSG_OVERFLOW(p) ((p)->overflow)
+
+//========================================
+// structs to hold individual DHCP options
+//========================================
+
+typedef struct {
+ UCHAR type;
+} DHCPOPT0;
+
+typedef struct {
+ UCHAR type;
+ UCHAR len;
+ UCHAR data;
+} DHCPOPT8;
+
+typedef struct {
+ UCHAR type;
+ UCHAR len;
+ ULONG data;
+} DHCPOPT32;
+
+#pragma pack()
+
+//==================
+// DHCP Option types
+//==================
+
+#define DHCP_MSG_TYPE 53 /* message type (u8) */
+#define DHCP_PARM_REQ 55 /* parameter request list: c1 (u8), ... */
+#define DHCP_CLIENT_ID 61 /* client ID: type (u8), i1 (u8), ... */
+#define DHCP_IP 50 /* requested IP addr (u32) */
+#define DHCP_NETMASK 1 /* subnet mask (u32) */
+#define DHCP_LEASE_TIME 51 /* lease time sec (u32) */
+#define DHCP_RENEW_TIME 58 /* renewal time sec (u32) */
+#define DHCP_REBIND_TIME 59 /* rebind time sec (u32) */
+#define DHCP_SERVER_ID 54 /* server ID: IP addr (u32) */
+#define DHCP_PAD 0
+#define DHCP_END 255
+
+//====================
+// DHCP Messages types
+//====================
+
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+#if DEBUG
+
+VOID
+DumpDHCP (const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ const int optlen);
+
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/endian.h b/src/VBox/HostDrivers/VBoxTAP/endian.h
new file mode 100644
index 000000000..3032dea53
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/endian.h
@@ -0,0 +1,39 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device
+ * functionality on Windows. Originally derived
+ * from the CIPE-Win32 project by Damion K. Wilson,
+ * with extensive modifications by James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef TAP_LITTLE_ENDIAN
+#define ntohs(x) RtlUshortByteSwap(x)
+#define htons(x) RtlUshortByteSwap(x)
+#define ntohl(x) RtlUlongByteSwap(x)
+#define htonl(x) RtlUlongByteSwap(x)
+#else
+#define ntohs(x) ((USHORT)(x))
+#define htons(x) ((USHORT)(x))
+#define ntohl(x) ((ULONG)(x))
+#define htonl(x) ((ULONG)(x))
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/error.c b/src/VBox/HostDrivers/VBoxTAP/error.c
new file mode 100644
index 000000000..3e52eb042
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/error.c
@@ -0,0 +1,382 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+const char *g_LastErrorFilename;
+int g_LastErrorLineNumber;
+
+#if DBG
+
+DebugOutput g_Debug;
+
+BOOLEAN
+NewlineExists (const char *str, int len)
+{
+ while (len-- > 0)
+ {
+ const char c = *str++;
+ if (c == '\n')
+ return TRUE;
+ else if (c == '\0')
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+MyDebugInit (unsigned int bufsiz)
+{
+ NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+ g_Debug.text = (char *) MemAlloc (bufsiz, FALSE);
+ if (g_Debug.text)
+ g_Debug.capacity = bufsiz;
+}
+
+VOID
+MyDebugFree ()
+{
+ if (g_Debug.text)
+ MemFree (g_Debug.text, g_Debug.capacity);
+ NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+}
+
+VOID
+MyDebugPrint (const unsigned char* format, ...)
+{
+ if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT)
+ {
+ BOOLEAN owned;
+ ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+ if (owned)
+ {
+ const int remaining = (int)g_Debug.capacity - (int)g_Debug.out;
+
+ if (remaining > 0)
+ {
+ va_list args;
+ NTSTATUS status;
+ char *end;
+
+ va_start (args, format);
+ status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out,
+ remaining,
+ &end,
+ NULL,
+ STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS,
+ format,
+ args);
+ va_end (args);
+
+ if (status == STATUS_SUCCESS)
+ g_Debug.out = end - g_Debug.text;
+ else
+ g_Debug.error = TRUE;
+ }
+ else
+ g_Debug.error = TRUE;
+
+ RELEASE_MUTEX (&g_Debug.lock);
+ }
+ else
+ g_Debug.error = TRUE;
+ }
+}
+
+BOOLEAN
+GetDebugLine (char *buf, const int len)
+{
+ static const char *truncated = "[OUTPUT TRUNCATED]\n";
+ BOOLEAN ret = FALSE;
+
+ NdisZeroMemory (buf, len);
+
+ if (g_Debug.text && g_Debug.capacity > 0)
+ {
+ BOOLEAN owned;
+ ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+ if (owned)
+ {
+ int i = 0;
+
+ if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in))
+ {
+ while (i < (len - 1) && g_Debug.in < g_Debug.out)
+ {
+ const char c = g_Debug.text[g_Debug.in++];
+ if (c == '\n')
+ break;
+ buf[i++] = c;
+ }
+ if (i < len)
+ buf[i] = '\0';
+ }
+
+ if (!i)
+ {
+ if (g_Debug.in == g_Debug.out)
+ {
+ g_Debug.in = g_Debug.out = 0;
+ if (g_Debug.error)
+ {
+ const unsigned int tlen = strlen (truncated);
+ if (tlen < g_Debug.capacity)
+ {
+ NdisMoveMemory (g_Debug.text, truncated, tlen+1);
+ g_Debug.out = tlen;
+ }
+ g_Debug.error = FALSE;
+ }
+ }
+ }
+ else
+ ret = TRUE;
+
+ RELEASE_MUTEX (&g_Debug.lock);
+ }
+ }
+ return ret;
+}
+
+VOID
+MyAssert (const unsigned char *file, int line)
+{
+ DEBUGP (("MYASSERT failed %s/%d\n", file, line));
+ KeBugCheckEx (0x0F00BABA,
+ (ULONG_PTR) line,
+ (ULONG_PTR) 0,
+ (ULONG_PTR) 0,
+ (ULONG_PTR) 0);
+}
+
+VOID
+PrMac (const MACADDR mac)
+{
+ DEBUGP (("%x:%x:%x:%x:%x:%x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]));
+}
+
+VOID
+PrIP (IPADDR ip_addr)
+{
+ const unsigned char *ip = (const unsigned char *) &ip_addr;
+
+ DEBUGP (("%d.%d.%d.%d",
+ ip[0], ip[1], ip[2], ip[3]));
+}
+
+const char *
+PrIPProto (int proto)
+{
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ return "UDP";
+ case IPPROTO_TCP:
+ return "TCP";
+ case IPPROTO_ICMP:
+ return "ICMP";
+ case IPPROTO_IGMP:
+ return "IGMP";
+ default:
+ return "???";
+ }
+}
+
+VOID
+DumpARP (const char *prefix, const ARP_PACKET *arp)
+{
+ DEBUGP (("%s ARP src=", prefix));
+ PrMac (arp->m_MAC_Source);
+ DEBUGP ((" dest="));
+ PrMac (arp->m_MAC_Destination);
+ DEBUGP ((" OP=0x%04x",
+ (int)ntohs(arp->m_ARP_Operation)));
+ DEBUGP ((" M=0x%04x(%d)",
+ (int)ntohs(arp->m_MAC_AddressType),
+ (int)arp->m_MAC_AddressSize));
+ DEBUGP ((" P=0x%04x(%d)",
+ (int)ntohs(arp->m_PROTO_AddressType),
+ (int)arp->m_PROTO_AddressSize));
+
+ DEBUGP ((" MacSrc="));
+ PrMac (arp->m_ARP_MAC_Source);
+ DEBUGP ((" MacDest="));
+ PrMac (arp->m_ARP_MAC_Destination);
+
+ DEBUGP ((" IPSrc="));
+ PrIP (arp->m_ARP_IP_Source);
+ DEBUGP ((" IPDest="));
+ PrIP (arp->m_ARP_IP_Destination);
+
+ DEBUGP (("\n"));
+}
+
+struct ethpayload {
+ ETH_HEADER eth;
+ UCHAR payload[DEFAULT_PACKET_LOOKAHEAD];
+};
+
+VOID
+DumpPacket2 (const char *prefix,
+ const ETH_HEADER *eth,
+ const unsigned char *data,
+ unsigned int len)
+{
+ struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE);
+ if (ep)
+ {
+ if (len > DEFAULT_PACKET_LOOKAHEAD)
+ len = DEFAULT_PACKET_LOOKAHEAD;
+ ep->eth = *eth;
+ NdisMoveMemory (ep->payload, data, len);
+ DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len);
+ MemFree (ep, sizeof (struct ethpayload));
+ }
+}
+
+VOID
+DumpPacket (const char *prefix,
+ const unsigned char *data,
+ unsigned int len)
+{
+ const ETH_HEADER *eth = (const ETH_HEADER *) data;
+ const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER));
+
+ if (len < sizeof (ETH_HEADER))
+ {
+ DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len));
+ return;
+ }
+
+ // ARP Packet?
+ if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP))
+ {
+ DumpARP (prefix, (const ARP_PACKET *) data);
+ return;
+ }
+
+ // IPv4 packet?
+ if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER))
+ && eth->proto == htons (ETH_P_IP)
+ && IPH_GET_VER (ip->version_len) == 4)
+ {
+ const int hlen = IPH_GET_LEN (ip->version_len);
+ const int blen = len - sizeof (ETH_HEADER);
+ BOOLEAN did = FALSE;
+
+ DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len));
+
+ if (!(ntohs (ip->tot_len) == blen && hlen <= blen))
+ {
+ DEBUGP ((" XXX"));
+ return;
+ }
+
+ // TCP packet?
+ if (ip->protocol == IPPROTO_TCP
+ && blen - hlen >= (sizeof (TCPHDR)))
+ {
+ const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+ DEBUGP ((" "));
+ PrIP (ip->saddr);
+ DEBUGP ((":%d", ntohs (tcp->source)));
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ DEBUGP ((":%d", ntohs (tcp->dest)));
+ did = TRUE;
+ }
+
+ // UDP packet?
+ else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0
+ && ip->protocol == IPPROTO_UDP
+ && blen - hlen >= (sizeof (UDPHDR)))
+ {
+ const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+
+ // DHCP packet?
+ if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT))
+ && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP)))
+ {
+ const DHCP *dhcp = (DHCP *) (data
+ + hlen
+ + sizeof (ETH_HEADER)
+ + sizeof (UDPHDR));
+
+ int optlen = len
+ - sizeof (ETH_HEADER)
+ - hlen
+ - sizeof (UDPHDR)
+ - sizeof (DHCP);
+
+ if (optlen < 0)
+ optlen = 0;
+
+ DumpDHCP (eth, ip, udp, dhcp, optlen);
+ did = TRUE;
+ }
+
+ if (!did)
+ {
+ DEBUGP ((" "));
+ PrIP (ip->saddr);
+ DEBUGP ((":%d", ntohs (udp->source)));
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ DEBUGP ((":%d", ntohs (udp->dest)));
+ did = TRUE;
+ }
+ }
+
+ if (!did)
+ {
+ DEBUGP ((" ipproto=%d ", ip->protocol));
+ PrIP (ip->saddr);
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ }
+
+ DEBUGP (("\n"));
+ return;
+ }
+
+ {
+ DEBUGP (("%s ??? src=", prefix));
+ PrMac (eth->src);
+ DEBUGP ((" dest="));
+ PrMac (eth->dest);
+ DEBUGP ((" proto=0x%04x len=%d\n",
+ (int) ntohs(eth->proto),
+ len));
+ }
+}
+
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/error.h b/src/VBox/HostDrivers/VBoxTAP/error.h
new file mode 100644
index 000000000..7860bb9f7
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/error.h
@@ -0,0 +1,103 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+#define NOTE_ERROR() \
+{ \
+ g_LastErrorFilename = __FILE__; \
+ g_LastErrorLineNumber = __LINE__; \
+}
+
+
+#ifdef DEBUG
+#define DEBUGP(fmt) { DbgPrint fmt; }
+#else
+#define DEBUGP(fmt)
+#endif
+
+#if DBG
+
+typedef struct {
+ unsigned int in;
+ unsigned int out;
+ unsigned int capacity;
+ char *text;
+ BOOLEAN error;
+ MUTEX lock;
+} DebugOutput;
+
+VOID MyDebugPrint (const unsigned char* format, ...);
+
+VOID MyAssert (const unsigned char *file, int line);
+
+VOID DumpPacket (const char *prefix,
+ const unsigned char *data,
+ unsigned int len);
+
+VOID DumpPacket2 (const char *prefix,
+ const ETH_HEADER *eth,
+ const unsigned char *data,
+ unsigned int len);
+
+#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL)
+
+#if ALSO_DBGPRINT
+#define DEBUGP(fmt) { DbgPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; }
+#else
+#define DEBUGP(fmt) { DbgPrint fmt; }
+#endif
+
+#define MYASSERT(exp) \
+{ \
+ if (!(exp)) \
+ { \
+ MyAssert(__FILE__, __LINE__); \
+ } \
+}
+
+#if DBG
+#define DUMP_PACKET(prefix, data, len) \
+ DumpPacket (prefix, data, len)
+
+#define DUMP_PACKET2(prefix, eth, data, len) \
+ DumpPacket2 (prefix, eth, data, len)
+#else
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+#endif
+
+#else
+
+#define MYASSERT(exp)
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/hexdump.c b/src/VBox/HostDrivers/VBoxTAP/hexdump.c
new file mode 100644
index 000000000..551377a7e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/hexdump.c
@@ -0,0 +1,74 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hexdump.h"
+
+#ifndef NDIS_MINIPORT_DRIVER
+
+VOID (*DbgMessage)(char *p_Format, ...) = DisplayDebugString;
+
+VOID DisplayDebugString (char *p_Format, ...)
+ {
+ static char l_Buffer [4096];
+
+ va_list l_ArgumentList;
+ va_start (l_ArgumentList, p_Format);
+ vsprintf (l_Buffer, p_Format, l_ArgumentList);
+ va_end (l_ArgumentList);
+
+ OutputDebugStringA (l_Buffer);
+ }
+
+#endif
+
+VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size)
+ {
+ unsigned long l_Index, l_Idx;
+ unsigned char l_Row [17];
+
+ for (l_Index = l_Row [16] = 0; l_Index < p_Size || l_Index % 16; ++l_Index)
+ {
+ if (l_Index % 16 == 0)
+ DEBUGP (("%05x ", l_Index));
+ DEBUGP (("%02x ", l_Row [l_Index % 16] = (l_Index < p_Size ? p_Buffer [l_Index] : 0)));
+ l_Row [l_Index % 16] = IfPrint (l_Row [l_Index % 16]);
+ if ((l_Index + 1) % 16 == 0)
+ DEBUGP ((" %s\n", l_Row));
+ }
+
+ DEBUGP (("\n"));
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/src/VBox/HostDrivers/VBoxTAP/hexdump.h b/src/VBox/HostDrivers/VBoxTAP/hexdump.h
new file mode 100644
index 000000000..4c8981213
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/hexdump.h
@@ -0,0 +1,68 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef HEXDUMP_DEFINED
+#define HEXDUMP_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//=====================================================================================
+// Debug Routines
+//=====================================================================================
+
+#ifndef NDIS_MINIPORT_DRIVER
+# include <stdio.h>
+# include <ctype.h>
+# include <windows.h>
+# include <winnt.h>
+# include <memory.h>
+
+# ifndef DEBUGP
+# define DEBUGP(fmt) { DbgMessage fmt; }
+# endif
+
+ extern VOID (*DbgMessage)(char *p_Format, ...);
+
+ VOID DisplayDebugString (char *p_Format, ...);
+#endif
+
+//===================================================================================
+// Reporting / Debugging
+//===================================================================================
+#define IfPrint(c) (c >= 32 && c < 127 ? c : '.')
+
+VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/VBox/HostDrivers/VBoxTAP/instance.c b/src/VBox/HostDrivers/VBoxTAP/instance.c
new file mode 100644
index 000000000..53c800c8e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/instance.c
@@ -0,0 +1,245 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device
+ * functionality on Windows. Originally derived
+ * from the CIPE-Win32 project by Damion K. Wilson,
+ * with extensive modifications by James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define INSTANCE_KEY(a) ((PVOID)((a)->m_Extension.m_TapDevice))
+
+#define N_INSTANCE_BUCKETS 256
+
+typedef struct _INSTANCE {
+ struct _INSTANCE *next;
+ TapAdapterPointer m_Adapter;
+} INSTANCE;
+
+typedef struct {
+ INSTANCE *list;
+ MUTEX lock;
+} INSTANCE_BUCKET;
+
+typedef struct {
+ INSTANCE_BUCKET buckets[N_INSTANCE_BUCKETS];
+} INSTANCE_HASH;
+
+INSTANCE_HASH *g_InstanceHash = NULL;
+
+// must return a hash >= 0 and < N_INSTANCE_BUCKETS
+int
+InstanceHashValue (PVOID addr)
+{
+ UCHAR *p = (UCHAR *) &addr;
+
+ if (sizeof (addr) == 4)
+ return p[0] ^ p[1] ^ p[2] ^ p[3];
+ else if (sizeof (addr) == 8)
+ return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ p[7];
+ else
+ {
+ MYASSERT (0);
+ }
+}
+
+BOOLEAN
+InitInstanceList (VOID)
+{
+ MYASSERT (g_InstanceHash == NULL);
+ g_InstanceHash = MemAlloc (sizeof (INSTANCE_HASH), TRUE);
+ if (g_InstanceHash)
+ {
+ int i;
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ INIT_MUTEX (&g_InstanceHash->buckets[i].lock);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+int
+NInstances (VOID)
+{
+ int i, n = 0;
+
+ if (g_InstanceHash)
+ {
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ {
+ BOOLEAN got_lock;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current;
+ for (current = ib->list; current != NULL; current = current->next)
+ ++n;
+ RELEASE_MUTEX (&ib->lock);
+ }
+ else
+ return -1;
+ }
+ }
+
+ return n;
+}
+
+int
+InstanceMaxBucketSize (VOID)
+{
+ int i, n = 0;
+
+ if (g_InstanceHash)
+ {
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ {
+ BOOLEAN got_lock;
+ int bucket_size = 0;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current;
+ for (current = ib->list; current != NULL; current = current->next)
+ ++bucket_size;
+ if (bucket_size > n)
+ n = bucket_size;
+ RELEASE_MUTEX (&ib->lock);
+ }
+ else
+ return -1;
+ }
+ }
+
+ return n;
+}
+
+VOID
+FreeInstanceList (VOID)
+{
+ if (g_InstanceHash)
+ {
+ MYASSERT (NInstances() == 0);
+ MemFree (g_InstanceHash, sizeof (INSTANCE_HASH));
+ g_InstanceHash = NULL;
+ }
+}
+
+BOOLEAN
+AddAdapterToInstanceList (TapAdapterPointer p_Adapter)
+{
+ BOOLEAN got_lock;
+ BOOLEAN ret = FALSE;
+ const int hash = InstanceHashValue(INSTANCE_KEY(p_Adapter));
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[hash];
+
+ DEBUGP (("[TAP] AddAdapterToInstanceList hash=%d\n", hash));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *i = MemAlloc (sizeof (INSTANCE), FALSE);
+ if (i)
+ {
+ MYASSERT (p_Adapter);
+ i->m_Adapter = p_Adapter;
+ i->next = ib->list;
+ ib->list = i;
+ ret = TRUE;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
+
+BOOLEAN
+RemoveAdapterFromInstanceList (TapAdapterPointer p_Adapter)
+{
+ BOOLEAN got_lock;
+ BOOLEAN ret = FALSE;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue(INSTANCE_KEY(p_Adapter))];
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current, *prev=NULL;
+ for (current = ib->list; current != NULL; current = current->next)
+ {
+ if (current->m_Adapter == p_Adapter) // found match
+ {
+ if (prev)
+ prev->next = current->next;
+ else
+ ib->list = current->next;
+ MemFree (current->m_Adapter, sizeof (TapAdapter));
+ MemFree (current, sizeof (INSTANCE));
+ ret = TRUE;
+ break;
+ }
+ prev = current;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
+
+TapAdapterPointer
+LookupAdapterInInstanceList (PDEVICE_OBJECT p_DeviceObject)
+{
+ BOOLEAN got_lock;
+ TapAdapterPointer ret = NULL;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue((PVOID)p_DeviceObject)];
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current, *prev=NULL;
+ for (current = ib->list; current != NULL; current = current->next)
+ {
+ if (p_DeviceObject == INSTANCE_KEY (current->m_Adapter)) // found match
+ {
+ // move it to head of list
+ if (prev)
+ {
+ prev->next = current->next;
+ current->next = ib->list;
+ ib->list = current;
+ }
+ ret = ib->list->m_Adapter;
+ break;
+ }
+ prev = current;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
diff --git a/src/VBox/HostDrivers/VBoxTAP/lock.h b/src/VBox/HostDrivers/VBoxTAP/lock.h
new file mode 100644
index 000000000..8598f319d
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/lock.h
@@ -0,0 +1,79 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device
+ * functionality on Windows. Originally derived
+ * from the CIPE-Win32 project by Damion K. Wilson,
+ * with extensive modifications by James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+typedef struct
+{
+ volatile long count;
+} MUTEX;
+
+#define MUTEX_SLEEP_TIME 10000 // microseconds
+
+#define INIT_MUTEX(m) { (m)->count = 0; }
+
+#define ACQUIRE_MUTEX_BLOCKING(m) \
+{ \
+ while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ NdisMSleep(MUTEX_SLEEP_TIME); \
+ } \
+}
+
+#define RELEASE_MUTEX(m) \
+{ \
+ NdisInterlockedDecrement(&((m)->count)); \
+}
+
+#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \
+{ \
+ if (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ result = FALSE; \
+ } \
+ else \
+ { \
+ result = TRUE; \
+ } \
+}
+
+#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \
+{ \
+ result = TRUE; \
+ while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ if (KeGetCurrentIrql () < DISPATCH_LEVEL) \
+ NdisMSleep(MUTEX_SLEEP_TIME); \
+ else \
+ { \
+ result = FALSE; \
+ break; \
+ } \
+ } \
+}
diff --git a/src/VBox/HostDrivers/VBoxTAP/macinfo.c b/src/VBox/HostDrivers/VBoxTAP/macinfo.c
new file mode 100644
index 000000000..131881887
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/macinfo.c
@@ -0,0 +1,159 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "macinfo.h"
+
+int
+HexStringToDecimalInt (const int p_Character)
+{
+ int l_Value = 0;
+
+ if (p_Character >= 'A' && p_Character <= 'F')
+ l_Value = (p_Character - 'A') + 10;
+ else if (p_Character >= 'a' && p_Character <= 'f')
+ l_Value = (p_Character - 'a') + 10;
+ else if (p_Character >= '0' && p_Character <= '9')
+ l_Value = p_Character - '0';
+
+ return l_Value;
+}
+
+BOOLEAN
+ParseMAC (MACADDR dest, const char *src)
+{
+ int c;
+ int mac_index = 0;
+ BOOLEAN high_digit = FALSE;
+ int delim_action = 1;
+
+ MYASSERT (src);
+ MYASSERT (dest);
+
+ CLEAR_MAC (dest);
+
+ while (c = *src++)
+ {
+ if (IsMacDelimiter (c))
+ {
+ mac_index += delim_action;
+ high_digit = FALSE;
+ delim_action = 1;
+ }
+ else if (IsHexDigit (c))
+ {
+ const int digit = HexStringToDecimalInt (c);
+ if (mac_index < sizeof (MACADDR))
+ {
+ if (!high_digit)
+ {
+ dest[mac_index] = (char)(digit);
+ high_digit = TRUE;
+ delim_action = 1;
+ }
+ else
+ {
+ dest[mac_index] = (char)(dest[mac_index] * 16 + digit);
+ ++mac_index;
+ high_digit = FALSE;
+ delim_action = 0;
+ }
+ }
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ return (mac_index + delim_action) >= sizeof (MACADDR);
+}
+
+/*
+ * Generate a MAC using the GUID in the adapter name.
+ *
+ * The mac is constructed as 00:FF:xx:xx:xx:xx where
+ * the Xs are taken from the first 32 bits of the GUID in the
+ * adapter name. This is similar to the Linux 2.4 tap MAC
+ * generator, except linux uses 32 random bits for the Xs.
+ *
+ * In general, this solution is reasonable for most
+ * applications except for very large bridged TAP networks,
+ * where the probability of address collisions becomes more
+ * than infintesimal.
+ *
+ * Using the well-known "birthday paradox", on a 1000 node
+ * network the probability of collision would be
+ * 0.000116292153. On a 10,000 node network, the probability
+ * of collision would be 0.01157288998621678766.
+ */
+
+VOID GenerateRandomMac (MACADDR mac, const unsigned char *adapter_name)
+{
+ unsigned const char *cp = adapter_name;
+ unsigned char c;
+ unsigned int i = 2;
+ unsigned int byte = 0;
+ int brace = 0;
+ int state = 0;
+
+ CLEAR_MAC (mac);
+
+ mac[0] = 0x00;
+ mac[1] = 0xFF;
+
+ while (c = *cp++)
+ {
+ if (i >= sizeof (MACADDR))
+ break;
+ if (c == '{')
+ brace = 1;
+ if (IsHexDigit (c) && brace)
+ {
+ const unsigned int digit = HexStringToDecimalInt (c);
+ if (state)
+ {
+ byte <<= 4;
+ byte |= digit;
+ mac[i++] = (unsigned char) byte;
+ state = 0;
+ }
+ else
+ {
+ byte = digit;
+ state = 1;
+ }
+ }
+ }
+}
+
+VOID GenerateRelatedMAC (MACADDR dest, const MACADDR src, const int delta)
+{
+ COPY_MAC (dest, src);
+ dest[2] += (UCHAR) delta;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxTAP/macinfo.h b/src/VBox/HostDrivers/VBoxTAP/macinfo.h
new file mode 100644
index 000000000..28c76d251
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/macinfo.h
@@ -0,0 +1,43 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MacInfoDefined
+#define MacInfoDefined
+
+//===================================================================================
+// Macros
+//===================================================================================
+#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.')
+#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
+
+#define COPY_MAC(dest, src) NdisMoveMemory ((dest), (src), sizeof (MACADDR))
+#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR))
+#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0)
+
+#endif
+
diff --git a/src/VBox/HostDrivers/VBoxTAP/mem.c b/src/VBox/HostDrivers/VBoxTAP/mem.c
new file mode 100644
index 000000000..5681fd4f0
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/mem.c
@@ -0,0 +1,190 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//------------------
+// Memory Management
+//------------------
+
+PVOID
+MemAlloc (ULONG p_Size, BOOLEAN zero)
+{
+ PVOID l_Return = NULL;
+
+ if (p_Size)
+ {
+ __try
+ {
+ if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
+ == NDIS_STATUS_SUCCESS)
+ {
+ if (zero)
+ NdisZeroMemory (l_Return, p_Size);
+ }
+ else
+ l_Return = NULL;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ l_Return = NULL;
+ }
+ }
+
+ return l_Return;
+}
+
+VOID
+MemFree (PVOID p_Addr, ULONG p_Size)
+{
+ if (p_Addr && p_Size)
+ {
+ __try
+ {
+#if DEBUG
+ NdisZeroMemory (p_Addr, p_Size);
+#endif
+ NdisFreeMemory (p_Addr, p_Size, 0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+}
+
+/*
+ * Circular queue management routines.
+ */
+
+#define QUEUE_BYTE_ALLOCATION(size) \
+ (sizeof (Queue) + (size * sizeof (PVOID)))
+
+#define QUEUE_ADD_INDEX(var, inc) \
+{ \
+ var += inc; \
+ if (var >= q->capacity) \
+ var -= q->capacity; \
+ MYASSERT (var < q->capacity); \
+}
+
+#define QUEUE_SANITY_CHECK() \
+ MYASSERT (q != NULL && q->base < q->capacity && q->size <= q->capacity)
+
+#define QueueCount(q) (q->size)
+
+#define UPDATE_MAX_SIZE() \
+{ \
+ if (q->size > q->max_size) \
+ q->max_size = q->size; \
+}
+
+Queue *
+QueueInit (ULONG capacity)
+{
+ Queue *q;
+
+ MYASSERT (capacity > 0);
+ q = (Queue *) MemAlloc (QUEUE_BYTE_ALLOCATION (capacity), TRUE);
+ if (!q)
+ return NULL;
+
+ q->base = q->size = 0;
+ q->capacity = capacity;
+ q->max_size = 0;
+ return q;
+}
+
+VOID
+QueueFree (Queue *q)
+{
+ if (q)
+ {
+ QUEUE_SANITY_CHECK ();
+ MemFree (q, QUEUE_BYTE_ALLOCATION (q->capacity));
+ }
+}
+
+PVOID
+QueuePush (Queue *q, PVOID item)
+{
+ ULONG dest;
+ QUEUE_SANITY_CHECK ();
+ if (q->size == q->capacity)
+ return NULL;
+ dest = q->base;
+ QUEUE_ADD_INDEX (dest, q->size);
+ q->data[dest] = item;
+ ++q->size;
+ UPDATE_MAX_SIZE();
+ return item;
+}
+
+PVOID
+QueuePop (Queue *q)
+{
+ ULONG oldbase;
+ QUEUE_SANITY_CHECK ();
+ if (!q->size)
+ return NULL;
+ oldbase = q->base;
+ QUEUE_ADD_INDEX (q->base, 1);
+ --q->size;
+ UPDATE_MAX_SIZE();
+ return q->data[oldbase];
+}
+
+PVOID
+QueueExtract (Queue *q, PVOID item)
+{
+ ULONG src, dest, count, n;
+ QUEUE_SANITY_CHECK ();
+ n = 0;
+ src = dest = q->base;
+ count = q->size;
+ while (count--)
+ {
+ if (item == q->data[src])
+ {
+ ++n;
+ --q->size;
+ }
+ else
+ {
+ q->data[dest] = q->data[src];
+ QUEUE_ADD_INDEX (dest, 1);
+ }
+ QUEUE_ADD_INDEX (src, 1);
+ }
+ if (n)
+ return item;
+ else
+ return NULL;
+}
+
+#undef QUEUE_BYTE_ALLOCATION
+#undef QUEUE_ADD_INDEX
+#undef QUEUE_SANITY_CHECK
+#undef UPDATE_MAX_SIZE
diff --git a/src/VBox/HostDrivers/VBoxTAP/proto.h b/src/VBox/HostDrivers/VBoxTAP/proto.h
new file mode 100644
index 000000000..6a70bebd7
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/proto.h
@@ -0,0 +1,168 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//============================================================
+// MAC address, Ethernet header, and ARP
+//============================================================
+
+#pragma pack(1)
+
+#define IP_HEADER_SIZE 20
+
+typedef unsigned char MACADDR [6];
+typedef unsigned long IPADDR;
+
+//-----------------
+// Ethernet address
+//-----------------
+
+typedef struct {
+ MACADDR addr;
+} ETH_ADDR;
+
+typedef struct {
+ ETH_ADDR list[NIC_MAX_MCAST_LIST];
+} MC_LIST;
+
+//----------------
+// Ethernet header
+//----------------
+
+typedef struct
+{
+ MACADDR dest; /* destination eth addr */
+ MACADDR src; /* source ether addr */
+
+# define ETH_P_IP 0x0800 /* IPv4 protocol */
+# define ETH_P_ARP 0x0806 /* ARP protocol */
+ USHORT proto; /* packet type ID field */
+} ETH_HEADER, *PETH_HEADER;
+
+//----------------
+// ARP packet
+//----------------
+
+typedef struct
+ {
+ MACADDR m_MAC_Destination; // Reverse these two
+ MACADDR m_MAC_Source; // to answer ARP requests
+ USHORT m_Proto; // 0x0806
+
+# define MAC_ADDR_TYPE 0x0001
+ USHORT m_MAC_AddressType; // 0x0001
+
+ USHORT m_PROTO_AddressType; // 0x0800
+ UCHAR m_MAC_AddressSize; // 0x06
+ UCHAR m_PROTO_AddressSize; // 0x04
+
+# define ARP_REQUEST 0x0001
+# define ARP_REPLY 0x0002
+ USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply
+
+ MACADDR m_ARP_MAC_Source;
+ IPADDR m_ARP_IP_Source;
+ MACADDR m_ARP_MAC_Destination;
+ IPADDR m_ARP_IP_Destination;
+ }
+ARP_PACKET, *PARP_PACKET;
+
+//----------
+// IP Header
+//----------
+
+typedef struct {
+# define IPH_GET_VER(v) (((v) >> 4) & 0x0F)
+# define IPH_GET_LEN(v) (((v) & 0x0F) << 2)
+ UCHAR version_len;
+
+ UCHAR tos;
+ USHORT tot_len;
+ USHORT id;
+
+# define IP_OFFMASK 0x1fff
+ USHORT frag_off;
+
+ UCHAR ttl;
+
+# define IPPROTO_UDP 17 /* UDP protocol */
+# define IPPROTO_TCP 6 /* TCP protocol */
+# define IPPROTO_ICMP 1 /* ICMP protocol */
+# define IPPROTO_IGMP 2 /* IGMP protocol */
+ UCHAR protocol;
+
+ USHORT check;
+ ULONG saddr;
+ ULONG daddr;
+ /* The options start here. */
+} IPHDR;
+
+//-----------
+// UDP header
+//-----------
+
+typedef struct {
+ USHORT source;
+ USHORT dest;
+ USHORT len;
+ USHORT check;
+} UDPHDR;
+
+//--------------------------
+// TCP header, per RFC 793.
+//--------------------------
+
+typedef struct {
+ USHORT source; /* source port */
+ USHORT dest; /* destination port */
+ ULONG seq; /* sequence number */
+ ULONG ack_seq; /* acknowledgement number */
+
+# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2)
+ UCHAR doff_res;
+
+# define TCPH_FIN_MASK (1<<0)
+# define TCPH_SYN_MASK (1<<1)
+# define TCPH_RST_MASK (1<<2)
+# define TCPH_PSH_MASK (1<<3)
+# define TCPH_ACK_MASK (1<<4)
+# define TCPH_URG_MASK (1<<5)
+# define TCPH_ECE_MASK (1<<6)
+# define TCPH_CWR_MASK (1<<7)
+ UCHAR flags;
+
+ USHORT window;
+ USHORT check;
+ USHORT urg_ptr;
+} TCPHDR;
+
+#define TCPOPT_EOL 0
+#define TCPOPT_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+
+#pragma pack()
diff --git a/src/VBox/HostDrivers/VBoxTAP/prototypes.h b/src/VBox/HostDrivers/VBoxTAP/prototypes.h
new file mode 100644
index 000000000..38395cd7e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/prototypes.h
@@ -0,0 +1,206 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TAP_PROTOTYPES_DEFINED
+#define TAP_PROTOTYPES_DEFINED
+
+NTSTATUS DriverEntry
+ (
+ IN PDRIVER_OBJECT p_DriverObject,
+ IN PUNICODE_STRING p_RegistryPath
+ );
+
+VOID TapDriverUnload
+ (
+ IN PDRIVER_OBJECT p_DriverObject
+ );
+
+NDIS_STATUS AdapterCreate
+ (
+ OUT PNDIS_STATUS p_ErrorStatus,
+ OUT PUINT p_MediaIndex,
+ IN PNDIS_MEDIUM p_Media,
+ IN UINT p_MediaCount,
+ IN NDIS_HANDLE p_AdapterHandle,
+ IN NDIS_HANDLE p_ConfigurationHandle
+ );
+
+VOID AdapterHalt
+ (
+ IN NDIS_HANDLE p_AdapterContext
+ );
+
+VOID AdapterFreeResources
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+NDIS_STATUS AdapterReset
+ (
+ OUT PBOOLEAN p_AddressingReset,
+ IN NDIS_HANDLE p_AdapterContext
+ );
+
+NDIS_STATUS AdapterQuery
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesWritten,
+ OUT PULONG p_BytesNeeded
+ );
+
+NDIS_STATUS AdapterModify
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesRead,
+ OUT PULONG p_BytesNeeded
+ );
+
+NDIS_STATUS AdapterTransmit
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN PNDIS_PACKET p_Packet,
+ IN UINT p_Flags
+ );
+
+NDIS_STATUS AdapterReceive
+ (
+ OUT PNDIS_PACKET p_Packet,
+ OUT PUINT p_Transferred,
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_HANDLE p_ReceiveContext,
+ IN UINT p_Offset,
+ IN UINT p_ToTransfer
+ );
+
+NTSTATUS TapDeviceHook
+ (
+ IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP
+ );
+
+NDIS_STATUS CreateTapDevice
+ (
+ TapExtensionPointer p_Extension,
+ const char *p_Name
+ );
+
+VOID DestroyTapDevice
+ (
+ TapExtensionPointer p_Extension
+ );
+
+VOID TapDeviceFreeResources
+ (
+ TapExtensionPointer p_Extension
+ );
+
+NTSTATUS CompleteIRP
+ (
+ IN PIRP p_IRP,
+ IN TapPacketPointer p_PacketBuffer,
+ IN CCHAR PriorityBoost
+ );
+
+VOID CancelIRPCallback
+ (
+ IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP
+ );
+
+VOID CancelIRP
+ (
+ TapExtensionPointer p_Extension,
+ IN PIRP p_IRP,
+ BOOLEAN callback
+ );
+
+VOID FlushQueues
+ (
+ TapExtensionPointer p_Extension
+ );
+
+VOID ResetTapAdapterState
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+BOOLEAN ProcessARP
+ (
+ TapAdapterPointer p_Adapter,
+ const PARP_PACKET src,
+ const IPADDR adapter_ip,
+ const IPADDR ip,
+ const MACADDR mac
+ );
+
+VOID SetMediaStatus
+ (
+ TapAdapterPointer p_Adapter,
+ BOOLEAN state
+ );
+
+VOID InjectPacket
+ (
+ TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len
+ );
+
+VOID CheckIfDhcpAndPointToPointMode
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+VOID HookDispatchFunctions();
+
+#if ENABLE_NONADMIN
+
+typedef struct _SECURITY_DESCRIPTOR {
+ unsigned char opaque[20];
+} SECURITY_DESCRIPTOR;
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwSetSecurityObject (
+ IN HANDLE Handle,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+VOID AllowNonAdmin (TapExtensionPointer p_Extension);
+
+#endif
+
+
+#endif
diff --git a/src/VBox/HostDrivers/VBoxTAP/tapdrvr.c b/src/VBox/HostDrivers/VBoxTAP/tapdrvr.c
new file mode 100644
index 000000000..ce8815aa6
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/tapdrvr.c
@@ -0,0 +1,2793 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device
+ * functionality on Windows. Originally derived
+ * from the CIPE-Win32 project by Damion K. Wilson,
+ * with extensive modifications by James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//======================================================
+// This driver is designed to work on Win 2000 or higher
+// versions of Windows.
+//
+// It is SMP-safe and handles NDIS 5 power management.
+//
+// By default we operate as a "tap" virtual ethernet
+// 802.3 interface, but we can emulate a "tun"
+// interface (point-to-point IPv4) through the
+// TAP_IOCTL_CONFIG_POINT_TO_POINT ioctl.
+//======================================================
+
+#define NDIS_MINIPORT_DRIVER
+#define BINARY_COMPATIBLE 0
+#define NDIS50_MINIPORT 1
+#define NDIS_WDM 0
+#define NDIS50 1
+#define NTSTRSAFE_LIB
+
+// Debug info output
+#define ALSO_DBGPRINT 1
+#define DEBUGP_AT_DISPATCH 0
+
+//========================================================
+// EXPERIMENTAL -- Configure TAP device object to be
+// accessible from non-administrative accounts, based
+// on an advanced properties setting.
+//
+// Duplicates the functionality of OpenVPN's
+// --allow-nonadmin directive.
+//========================================================
+#define ENABLE_NONADMIN 1 // JYFIXME
+
+
+#include <ndis.h>
+#include <ntstrsafe.h>
+
+#include "lock.h"
+#include "constants.h"
+#include "common.h"
+#include "proto.h"
+#include "error.h"
+#include "endian.h"
+#include "dhcp.h"
+#include "types.h"
+#include "prototypes.h"
+
+#include "mem.c"
+#include "macinfo.c"
+#include "error.c"
+#include "dhcp.c"
+#include "instance.c"
+
+#ifdef VBOX
+#include <VBox/tapwin32.h>
+#endif
+
+#define IS_UP(ta) \
+ ((ta)->m_InterfaceIsRunning && (ta)->m_Extension.m_TapIsRunning)
+
+#define INCREMENT_STAT(s) ++(s)
+
+#define NAME_BUFFER_SIZE 80
+
+//========================================================
+// Globals
+//========================================================
+
+NDIS_HANDLE g_NdisWrapperHandle;
+
+const UINT g_SupportedOIDList[] = {
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_SUPPORTED_LIST
+};
+
+//============================================================
+// Driver Entry
+//============================================================
+#pragma NDIS_INIT_FUNCTION (DriverEntry)
+
+NTSTATUS
+DriverEntry (IN PDRIVER_OBJECT p_DriverObject,
+ IN PUNICODE_STRING p_RegistryPath)
+{
+ NDIS_STATUS l_Status = NDIS_STATUS_FAILURE;
+ NDIS_MINIPORT_CHARACTERISTICS *l_Properties = NULL;
+
+ //========================================================
+ // Notify NDIS that a new miniport driver is initializing.
+ //========================================================
+
+ NdisMInitializeWrapper (&g_NdisWrapperHandle,
+ p_DriverObject,
+ p_RegistryPath, NULL);
+
+ //======================
+ // Global initialization
+ //======================
+
+#if DBG
+ MyDebugInit (10000); // Allocate debugging text space
+#endif
+
+ if (!InitInstanceList ())
+ {
+ DEBUGP (("[TAP] Allocation failed for adapter instance list\n"));
+ goto cleanup;
+ }
+
+ //=======================================
+ // Set and register miniport entry points
+ //=======================================
+
+ l_Properties = MemAlloc (sizeof (NDIS_MINIPORT_CHARACTERISTICS), TRUE);
+
+ if (l_Properties == NULL)
+ {
+ DEBUGP (("[TAP] Allocation failed for miniport entry points\n"));
+ goto cleanup;
+ }
+
+ l_Properties->MajorNdisVersion = TAP_NDIS_MAJOR_VERSION;
+ l_Properties->MinorNdisVersion = TAP_NDIS_MINOR_VERSION;
+ l_Properties->InitializeHandler = AdapterCreate;
+ l_Properties->HaltHandler = AdapterHalt;
+ l_Properties->ResetHandler = AdapterReset; /* DISPATCH_LEVEL */
+ l_Properties->TransferDataHandler = AdapterReceive; /* DISPATCH_LEVEL */
+ l_Properties->SendHandler = AdapterTransmit; /* DISPATCH_LEVEL */
+ l_Properties->QueryInformationHandler = AdapterQuery; /* DISPATCH_LEVEL */
+ l_Properties->SetInformationHandler = AdapterModify; /* DISPATCH_LEVEL */
+
+ switch (l_Status =
+ NdisMRegisterMiniport (g_NdisWrapperHandle, l_Properties,
+ sizeof (NDIS_MINIPORT_CHARACTERISTICS)))
+ {
+ case NDIS_STATUS_SUCCESS:
+ {
+ DEBUGP (("[TAP] version [%d.%d] %s %s registered miniport successfully\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__));
+ DEBUGP (("Registry Path: '%S'\n", p_RegistryPath->Buffer));
+ break;
+ }
+
+ case NDIS_STATUS_BAD_CHARACTERISTICS:
+ {
+ DEBUGP (("[TAP] Miniport characteristics were badly defined\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ case NDIS_STATUS_BAD_VERSION:
+ {
+ DEBUGP
+ (("[TAP] NDIS Version is wrong for the given characteristics\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ case NDIS_STATUS_RESOURCES:
+ {
+ DEBUGP (("[TAP] Insufficient resources\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ default:
+ case NDIS_STATUS_FAILURE:
+ {
+ DEBUGP (("[TAP] Unknown fatal registration error\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+ }
+
+ cleanup:
+ if (l_Properties)
+ MemFree (l_Properties, sizeof (NDIS_MINIPORT_CHARACTERISTICS));
+
+ if (l_Status == NDIS_STATUS_SUCCESS)
+ NdisMRegisterUnloadHandler (g_NdisWrapperHandle, TapDriverUnload);
+ else
+ TapDriverUnload (p_DriverObject);
+
+ return l_Status;
+}
+
+//============================================================
+// Driver Unload
+//============================================================
+VOID
+TapDriverUnload (IN PDRIVER_OBJECT p_DriverObject)
+{
+ DEBUGP (("[TAP] version [%d.%d] %s %s unloaded, instances=%d, imbs=%d\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__,
+ NInstances(),
+ InstanceMaxBucketSize()));
+
+ FreeInstanceList ();
+
+ //==============================
+ // Free debugging text space
+ //==============================
+#if DBG
+ MyDebugFree ();
+#endif
+}
+
+//==========================================================
+// Adapter Initialization
+//==========================================================
+NDIS_STATUS AdapterCreate
+ (OUT PNDIS_STATUS p_ErrorStatus,
+ OUT PUINT p_MediaIndex,
+ IN PNDIS_MEDIUM p_Media,
+ IN UINT p_MediaCount,
+ IN NDIS_HANDLE p_AdapterHandle,
+ IN NDIS_HANDLE p_ConfigurationHandle)
+{
+ TapAdapterPointer l_Adapter = NULL;
+
+ NDIS_MEDIUM l_PreferredMedium = NdisMedium802_3; // Ethernet
+ BOOLEAN l_MacFromRegistry = FALSE;
+ UINT l_Index;
+#ifndef VBOX
+ NDIS_STATUS status;
+#endif
+
+#if ENABLE_NONADMIN
+ BOOLEAN enable_non_admin = FALSE;
+#endif
+
+ //====================================
+ // Make sure adapter type is supported
+ //====================================
+
+ for (l_Index = 0;
+ l_Index < p_MediaCount && p_Media[l_Index] != l_PreferredMedium;
+ ++l_Index);
+
+ if (l_Index == p_MediaCount)
+ {
+ DEBUGP (("[TAP] Unsupported adapter type [wanted: %d]\n",
+ l_PreferredMedium));
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ *p_MediaIndex = l_Index;
+
+ //=========================================
+ // Allocate memory for TapAdapter structure
+ //=========================================
+
+ l_Adapter = MemAlloc (sizeof (TapAdapter), TRUE);
+
+ if (l_Adapter == NULL)
+ {
+ DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //==========================================
+ // Inform the NDIS library about significant
+ // features of our virtual NIC.
+ //==========================================
+
+ NdisMSetAttributesEx
+ (p_AdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ 16,
+ NDIS_ATTRIBUTE_DESERIALIZE
+ | NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
+ | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT
+ | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal);
+
+ //=====================================
+ // Initialize simple Adapter parameters
+ //=====================================
+
+ l_Adapter->m_Lookahead = DEFAULT_PACKET_LOOKAHEAD;
+ l_Adapter->m_Medium = l_PreferredMedium;
+ l_Adapter->m_DeviceState = '?';
+ l_Adapter->m_MiniportAdapterHandle = p_AdapterHandle;
+
+ //==================================
+ // Allocate spinlock for controlling
+ // access to multicast address list.
+ //==================================
+ NdisAllocateSpinLock (&l_Adapter->m_MCLock);
+ l_Adapter->m_MCLockAllocated = TRUE;
+
+ //====================================================
+ // Register a shutdown handler which will be called
+ // on system restart/shutdown to halt our virtual NIC.
+ //====================================================
+
+ NdisMRegisterAdapterShutdownHandler (p_AdapterHandle, l_Adapter,
+ AdapterHalt);
+ l_Adapter->m_RegisteredAdapterShutdownHandler = TRUE;
+
+ //============================================
+ // Get parameters from registry which were set
+ // in the adapter advanced properties dialog.
+ //============================================
+ {
+ NDIS_STATUS status;
+ NDIS_HANDLE configHandle;
+ NDIS_CONFIGURATION_PARAMETER *parm;
+
+ // set defaults in case our registry query fails
+ l_Adapter->m_MTU = ETHERNET_MTU;
+ l_Adapter->m_MediaStateAlwaysConnected = FALSE;
+ l_Adapter->m_MediaState = FALSE;
+
+ NdisOpenConfiguration (&status, &configHandle, p_ConfigurationHandle);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] Couldn't open adapter registry\n"));
+ AdapterFreeResources (l_Adapter);
+ return status;
+ }
+
+ //====================================
+ // Allocate and construct adapter name
+ //====================================
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MiniportName");
+ NdisReadConfiguration (&status, &parm, configHandle, &key, NdisParameterString);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterString)
+ {
+ DEBUGP (("[TAP] NdisReadConfiguration (MiniportName=%s)\n", parm->ParameterData.StringData.Buffer));
+
+ if (RtlUnicodeStringToAnsiString (
+ &l_Adapter->m_NameAnsi,
+ &parm->ParameterData.StringData,
+ TRUE) != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] RtlUnicodeStringToAnsiString MiniportName failed\n"));
+ status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ } else {
+ /* "MiniportName" is available only XP and above. Not on Windows 2000. */
+ NDIS_STRING key = NDIS_STRING_CONST("NdisVersion");
+ NdisReadConfiguration (&status, &parm, configHandle, &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterData.IntegerData == 0x50000)
+ {
+ /* Fallback for Windows 2000 with NDIS version 5.00.00
+ Don't use this on Vista, 'NDIS_MINIPORT_BLOCK' was changed! */
+ DEBUGP (("[TAP] NdisReadConfiguration NdisVersion (Int=%X)\n", parm->ParameterData.IntegerData));
+ if (RtlUnicodeStringToAnsiString (
+ &l_Adapter->m_NameAnsi,
+ &((PNDIS_MINIPORT_BLOCK) p_AdapterHandle)->MiniportName,
+ TRUE) != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] RtlUnicodeStringToAnsiString MiniportName (W2K) failed\n"));
+ status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ }
+ }
+ }
+
+ /* Can't continue without name (see macro 'NAME') */
+ if (status != NDIS_STATUS_SUCCESS || !l_Adapter->m_NameAnsi.Buffer)
+ {
+ NdisCloseConfiguration (configHandle);
+ AdapterFreeResources (l_Adapter);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ /* Read MTU setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MTU");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ int mtu = parm->ParameterData.IntegerData;
+ if (mtu < MINIMUM_MTU)
+ mtu = MINIMUM_MTU;
+ if (mtu > MAXIMUM_MTU)
+ mtu = MAXIMUM_MTU;
+ l_Adapter->m_MTU = mtu;
+ }
+ }
+ }
+
+ /* Read Media Status setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MediaStatus");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ if (parm->ParameterData.IntegerData)
+ {
+ l_Adapter->m_MediaStateAlwaysConnected = TRUE;
+ l_Adapter->m_MediaState = TRUE;
+ }
+ }
+ }
+ }
+
+#if ENABLE_NONADMIN
+ /* Read AllowNonAdmin setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("AllowNonAdmin");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ if (parm->ParameterData.IntegerData)
+ {
+ enable_non_admin = TRUE;
+ }
+ }
+ }
+ }
+#endif
+
+ /* Read optional MAC setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MAC");
+ ANSI_STRING mac_string;
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterString);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterString)
+ {
+ if (RtlUnicodeStringToAnsiString (&mac_string, &parm->ParameterData.StringData, TRUE) == STATUS_SUCCESS)
+ {
+ l_MacFromRegistry = ParseMAC (l_Adapter->m_MAC, mac_string.Buffer);
+ RtlFreeAnsiString (&mac_string);
+ }
+ }
+ }
+ }
+
+ NdisCloseConfiguration (configHandle);
+
+ DEBUGP (("[%s] MTU=%d\n", NAME (l_Adapter), l_Adapter->m_MTU));
+ }
+
+ //==================================
+ // Store and update MAC address info
+ //==================================
+
+ if (!l_MacFromRegistry)
+ GenerateRandomMac (l_Adapter->m_MAC, NAME (l_Adapter));
+
+ DEBUGP (("[%s] Using MAC %x:%x:%x:%x:%x:%x\n",
+ NAME (l_Adapter),
+ l_Adapter->m_MAC[0], l_Adapter->m_MAC[1], l_Adapter->m_MAC[2],
+ l_Adapter->m_MAC[3], l_Adapter->m_MAC[4], l_Adapter->m_MAC[5]));
+
+ //==================
+ // Set broadcast MAC
+ //==================
+ {
+ int i;
+ for (i = 0; i < sizeof (MACADDR); ++i)
+ l_Adapter->m_MAC_Broadcast[i] = 0xFF;
+ }
+
+ //====================================
+ // Initialize TAP device
+ //====================================
+ {
+ NDIS_STATUS tap_status;
+ tap_status = CreateTapDevice (&l_Adapter->m_Extension, NAME (l_Adapter));
+ if (tap_status != NDIS_STATUS_SUCCESS)
+ {
+ AdapterFreeResources (l_Adapter);
+ return tap_status;
+ }
+ }
+
+ if (!AddAdapterToInstanceList (l_Adapter))
+ {
+ NOTE_ERROR ();
+ TapDeviceFreeResources (&l_Adapter->m_Extension);
+ AdapterFreeResources (l_Adapter);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ l_Adapter->m_InterfaceIsRunning = TRUE;
+
+#if ENABLE_NONADMIN
+ if (enable_non_admin)
+ AllowNonAdmin (&l_Adapter->m_Extension);
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+AdapterHalt (IN NDIS_HANDLE p_AdapterContext)
+{
+ BOOLEAN status;
+
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+
+ NOTE_ERROR ();
+
+ l_Adapter->m_InterfaceIsRunning = FALSE;
+
+ DEBUGP (("[%s] is being halted\n", NAME (l_Adapter)));
+
+ DestroyTapDevice (&l_Adapter->m_Extension);
+
+ // Free resources
+ DEBUGP (("[%s] Freeing Resources\n", NAME (l_Adapter)));
+ AdapterFreeResources (l_Adapter);
+
+ status = RemoveAdapterFromInstanceList (l_Adapter);
+ DEBUGP (("[TAP] RemoveAdapterFromInstanceList returned %d\n", (int) status));
+
+ DEBUGP (("[TAP] version [%d.%d] %s %s AdapterHalt returning\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__));
+}
+
+VOID
+AdapterFreeResources (TapAdapterPointer p_Adapter)
+{
+ MYASSERT (!p_Adapter->m_CalledAdapterFreeResources);
+ p_Adapter->m_CalledAdapterFreeResources = TRUE;
+
+ if (p_Adapter->m_NameAnsi.Buffer)
+ RtlFreeAnsiString (&p_Adapter->m_NameAnsi);
+
+ if (p_Adapter->m_RegisteredAdapterShutdownHandler)
+ NdisMDeregisterAdapterShutdownHandler (p_Adapter->m_MiniportAdapterHandle);
+
+ if (p_Adapter->m_MCLockAllocated)
+ NdisFreeSpinLock (&l_Adapter->m_MCLock);
+}
+
+VOID
+DestroyTapDevice (TapExtensionPointer p_Extension)
+{
+ DEBUGP (("[%s] Destroying tap device\n", p_Extension->m_TapName));
+
+ //======================================
+ // Let clients know we are shutting down
+ //======================================
+ p_Extension->m_TapIsRunning = FALSE;
+ p_Extension->m_TapOpens = 0;
+ p_Extension->m_Halt = TRUE;
+
+ //=====================================
+ // If we are concurrently executing in
+ // TapDeviceHook or AdapterTransmit,
+ // give those calls time to finish.
+ // Note that we must be running at IRQL
+ // < DISPATCH_LEVEL in order to call
+ // NdisMSleep.
+ //=====================================
+ NdisMSleep (500000);
+
+ //===========================================================
+ // Exhaust IRP and packet queues. Any pending IRPs will
+ // be cancelled, causing user-space to get this error
+ // on overlapped reads:
+ // The I/O operation has been aborted because of either a
+ // thread exit or an application request. (code=995)
+ // It's important that user-space close the device handle
+ // when this code is returned, so that when we finally
+ // do a NdisMDeregisterDevice, the device reference count
+ // is 0. Otherwise the driver will not unload even if the
+ // the last adapter has been halted.
+ //===========================================================
+ FlushQueues (p_Extension);
+ NdisMSleep (500000); // give user space time to respond to IRP cancel
+
+ TapDeviceFreeResources (p_Extension);
+}
+
+VOID
+TapDeviceFreeResources (TapExtensionPointer p_Extension)
+{
+ MYASSERT (p_Extension);
+ MYASSERT (!p_Extension->m_CalledTapDeviceFreeResources);
+ p_Extension->m_CalledTapDeviceFreeResources = TRUE;
+
+ if (p_Extension->m_PacketQueue)
+ QueueFree (p_Extension->m_PacketQueue);
+ if (p_Extension->m_IrpQueue)
+ QueueFree (p_Extension->m_IrpQueue);
+
+ if (p_Extension->m_CreatedUnicodeLinkName)
+ RtlFreeUnicodeString (&p_Extension->m_UnicodeLinkName);
+
+ //==========================================================
+ // According to DDK docs, the device is not actually deleted
+ // until its reference count falls to zero. That means we
+ // still need to gracefully fail TapDeviceHook requests
+ // after this point, otherwise ugly things would happen if
+ // the device was disabled (e.g. in the network connections
+ // control panel) while a userspace app still held an open
+ // file handle to it.
+ //==========================================================
+
+ if (p_Extension->m_TapDevice)
+ {
+ BOOLEAN status;
+ status = (NdisMDeregisterDevice (p_Extension->m_TapDeviceHandle)
+ == NDIS_STATUS_SUCCESS);
+ DEBUGP (("[TAP] Deregistering TAP device, status=%d\n", (int)status));
+ }
+
+ if (p_Extension->m_TapName)
+ MemFree (p_Extension->m_TapName, NAME_BUFFER_SIZE);
+
+ if (p_Extension->m_AllocatedSpinlocks)
+ NdisFreeSpinLock (&p_Extension->m_QueueLock);
+}
+
+//========================================================================
+// Tap Device Initialization
+//========================================================================
+
+NDIS_STATUS
+CreateTapDevice (TapExtensionPointer p_Extension, const char *p_Name)
+{
+# define SIZEOF_DISPATCH (sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1))
+ PDRIVER_DISPATCH *l_Dispatch = NULL;
+ ANSI_STRING l_TapString, l_LinkString;
+ UNICODE_STRING l_TapUnicode;
+ BOOLEAN l_FreeTapUnicode = FALSE;
+ NTSTATUS l_Status, l_Return = NDIS_STATUS_SUCCESS;
+ const char *l_UsableName;
+
+ DEBUGP (("[TAP] version [%d.%d] creating tap device: %s\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ p_Name));
+
+ NdisZeroMemory (p_Extension, sizeof (TapExtension));
+
+ INIT_MUTEX (&p_Extension->m_OpenCloseMutex);
+
+ l_LinkString.Buffer = NULL;
+ l_TapString.Buffer = NULL;
+
+ l_TapString.MaximumLength = l_LinkString.MaximumLength = NAME_BUFFER_SIZE;
+
+ //=======================================
+ // Set TAP device entry points
+ //=======================================
+
+ if ((l_Dispatch = MemAlloc (SIZEOF_DISPATCH, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP dispatch table\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ l_Dispatch[IRP_MJ_DEVICE_CONTROL] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_READ] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_WRITE] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_CREATE] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_CLOSE] = TapDeviceHook;
+
+ //==================================
+ // Find the beginning of the GUID
+ //==================================
+ l_UsableName = p_Name;
+ while (*l_UsableName != '{')
+ {
+ if (*l_UsableName == '\0')
+ {
+ DEBUGP (("[%s] couldn't find leading '{' in name\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ ++l_UsableName;
+ }
+
+ //==================================
+ // Allocate pool for TAP device name
+ //==================================
+
+ if ((p_Extension->m_TapName = l_TapString.Buffer =
+ MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP name buffer\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //================================================
+ // Allocate pool for TAP symbolic link name buffer
+ //================================================
+
+ if ((l_LinkString.Buffer =
+ MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP symbolic link name buffer\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //=======================================================
+ // Set TAP device name
+ //=======================================================
+
+ l_Status = RtlStringCchPrintfExA
+ (l_TapString.Buffer,
+ l_TapString.MaximumLength,
+ NULL,
+ NULL,
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+ "%s%s%s",
+ SYSDEVICEDIR,
+ l_UsableName,
+ TAPSUFFIX);
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't format TAP device name\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_TapString.Length = (USHORT) strlen (l_TapString.Buffer);
+
+ DEBUGP (("TAP DEV NAME: '%s'\n", l_TapString.Buffer));
+
+ //=======================================================
+ // Set TAP link name
+ //=======================================================
+
+ l_Status = RtlStringCchPrintfExA
+ (l_LinkString.Buffer,
+ l_LinkString.MaximumLength,
+ NULL,
+ NULL,
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+ "%s%s%s",
+ USERDEVICEDIR,
+ l_UsableName,
+ TAPSUFFIX);
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't format TAP device symbolic link\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_LinkString.Length = (USHORT) strlen (l_LinkString.Buffer);
+
+ DEBUGP (("TAP LINK NAME: '%s'\n", l_LinkString.Buffer));
+
+ //==================================================
+ // Convert strings to unicode
+ //==================================================
+ if (RtlAnsiStringToUnicodeString (&l_TapUnicode, &l_TapString, TRUE) !=
+ STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP unicode name buffer\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_FreeTapUnicode = TRUE;
+
+ if (RtlAnsiStringToUnicodeString
+ (&p_Extension->m_UnicodeLinkName, &l_LinkString, TRUE)
+ != STATUS_SUCCESS)
+ {
+ DEBUGP
+ (("[%s] Couldn't allocate unicode string for symbolic link name\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ p_Extension->m_CreatedUnicodeLinkName = TRUE;
+
+ //==================================================
+ // Create new TAP device with symbolic
+ // link and associate with adapter.
+ //==================================================
+
+ l_Status = NdisMRegisterDevice
+ (g_NdisWrapperHandle,
+ &l_TapUnicode,
+ &p_Extension->m_UnicodeLinkName,
+ l_Dispatch,
+ &p_Extension->m_TapDevice,
+ &p_Extension->m_TapDeviceHandle
+ );
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't be created\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ /* Set TAP device flags */
+ p_Extension->m_TapDevice->Flags |= DO_DIRECT_IO;
+
+ //========================================================
+ // Initialize Packet and IRP queues.
+ //
+ // The packet queue is used to buffer data which has been
+ // "transmitted" by the virtual NIC, before user space
+ // has had a chance to read it.
+ //
+ // The IRP queue is used to buffer pending I/O requests
+ // from userspace, i.e. read requests on the TAP device
+ // waiting for the system to "transmit" something through
+ // the virtual NIC.
+ //
+ // Basically, packets in the packet queue are used
+ // to satisfy IRP requests in the IRP queue.
+ //
+ // QueueLock is used to lock the packet queue used
+ // for the TAP-Win32 NIC -> User Space packet flow direction.
+ //
+ // All accesses to packet or IRP queues should be
+ // bracketed by the QueueLock spinlock,
+ // in order to be SMP-safe.
+ //========================================================
+
+ NdisAllocateSpinLock (&p_Extension->m_QueueLock);
+ p_Extension->m_AllocatedSpinlocks = TRUE;
+
+ p_Extension->m_PacketQueue = QueueInit (PACKET_QUEUE_SIZE);
+ p_Extension->m_IrpQueue = QueueInit (IRP_QUEUE_SIZE);
+
+ if (!p_Extension->m_PacketQueue
+ || !p_Extension->m_IrpQueue)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP queues\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //========================
+ // Finalize initialization
+ //========================
+
+ p_Extension->m_TapIsRunning = TRUE;
+
+ DEBUGP (("[%s] successfully created TAP device [%s]\n", p_Name,
+ p_Extension->m_TapName));
+
+ cleanup:
+ if (l_FreeTapUnicode)
+ RtlFreeUnicodeString (&l_TapUnicode);
+ if (l_LinkString.Buffer)
+ MemFree (l_LinkString.Buffer, NAME_BUFFER_SIZE);
+ if (l_Dispatch)
+ MemFree (l_Dispatch, SIZEOF_DISPATCH);
+
+ if (l_Return != NDIS_STATUS_SUCCESS)
+ TapDeviceFreeResources (p_Extension);
+
+ return l_Return;
+}
+#undef SIZEOF_DISPATCH
+
+//========================================================
+// Adapter Control
+//========================================================
+NDIS_STATUS
+AdapterReset (OUT PBOOLEAN p_AddressingReset, IN NDIS_HANDLE p_AdapterContext)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ DEBUGP (("[%s] is resetting\n", NAME (l_Adapter)));
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS AdapterReceive
+ (OUT PNDIS_PACKET p_Packet,
+ OUT PUINT p_Transferred,
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_HANDLE p_ReceiveContext,
+ IN UINT p_Offset,
+ IN UINT p_ToTransfer)
+{
+ DEBUGP(("AdapterReceive %08x size=%x\n", p_Packet, p_ToTransfer));
+ return NDIS_STATUS_SUCCESS;
+}
+
+//==============================================================
+// Adapter Option Query/Modification
+//==============================================================
+NDIS_STATUS AdapterQuery
+(IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesWritten, OUT PULONG p_BytesNeeded)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ TapAdapterQuery l_Query, *l_QueryPtr = &l_Query;
+ NDIS_STATUS l_Status = NDIS_STATUS_SUCCESS;
+ UINT l_QueryLength = 4;
+#ifndef VBOX
+ BOOLEAN lock_succeeded;
+#endif
+
+ NdisZeroMemory (&l_Query, sizeof (l_Query));
+
+ switch (p_OID)
+ {
+ //===================================================================
+ // Vendor & Driver version Info
+ //===================================================================
+ case OID_GEN_VENDOR_DESCRIPTION:
+ l_QueryPtr = (TapAdapterQueryPointer) PRODUCT_STRING;
+ l_QueryLength = strlen (PRODUCT_STRING) + 1;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ l_Query.m_Long = 0xffffff;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ l_Query.m_Short =
+ (((USHORT) TAP_NDIS_MAJOR_VERSION) << 8 | (USHORT)
+ TAP_NDIS_MINOR_VERSION);
+ l_QueryLength = sizeof (unsigned short);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ l_Query.m_Long =
+ (((USHORT) TAP_DRIVER_MAJOR_VERSION) << 8 | (USHORT)
+ TAP_DRIVER_MINOR_VERSION);
+ break;
+
+ //=================================================================
+ // Statistics
+ //=================================================================
+ case OID_GEN_RCV_NO_BUFFER:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ l_Query.m_Long = l_Adapter->m_Tx;
+ break;
+
+ case OID_GEN_RCV_OK:
+ l_Query.m_Long = l_Adapter->m_Rx;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ l_Query.m_Long = l_Adapter->m_TxErr;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ l_Query.m_Long = l_Adapter->m_RxErr;
+ break;
+
+ //===================================================================
+ // Device & Protocol Options
+ //===================================================================
+ case OID_GEN_SUPPORTED_LIST:
+ l_QueryPtr = (TapAdapterQueryPointer) g_SupportedOIDList;
+ l_QueryLength = sizeof (g_SupportedOIDList);
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ // This MUST be here !!!
+ l_Query.m_Long = (NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
+ | NDIS_MAC_OPTION_NO_LOOPBACK
+ | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND);
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ l_Query.m_Long =
+ (NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL);
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+ l_Query.m_Long = 0;
+ break;
+
+ //==================================================================
+ // Device Info
+ //==================================================================
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ l_Query.m_Long = l_Adapter->m_MediaState
+ ? NdisMediaStateConnected : NdisMediaStateDisconnected;
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ l_Query.m_HardwareStatus = NdisHardwareStatusReady;
+ l_QueryLength = sizeof (NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ l_Query.m_Medium = l_Adapter->m_Medium;
+ l_QueryLength = sizeof (NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_PHYSICAL_MEDIUM:
+ l_Query.m_PhysicalMedium = NdisPhysicalMediumUnspecified;
+ l_QueryLength = sizeof (NDIS_PHYSICAL_MEDIUM);
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ l_Query.m_Long = 100000;
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ COPY_MAC (l_Query.m_MacAddress, l_Adapter->m_MAC);
+ l_QueryLength = sizeof (MACADDR);
+ break;
+
+ //==================================================================
+ // Limits
+ //==================================================================
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ l_Query.m_Long = 1;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ l_Query.m_Long = NIC_MAX_MCAST_LIST;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ l_Query.m_Long = l_Adapter->m_Lookahead;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ l_Query.m_Long = DEFAULT_PACKET_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ l_Query.m_Long = l_Adapter->m_MTU;
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ do
+ {
+ PNDIS_PNP_CAPABILITIES pPNPCapabilities;
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
+
+ if (p_BufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
+ {
+ pPNPCapabilities = (PNDIS_PNP_CAPABILITIES) (p_Buffer);
+
+ //
+ // Setting up the buffer to be returned
+ // to the Protocol above the Passthru miniport
+ //
+ pPMstruct = &pPNPCapabilities->WakeUpCapabilities;
+ pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ }
+ l_QueryLength = sizeof (NDIS_PNP_CAPABILITIES);
+ }
+ while (FALSE);
+ break;
+ case OID_PNP_QUERY_POWER:
+ break;
+
+ // Required OIDs that we don't support
+
+ case OID_GEN_SUPPORTED_GUIDS:
+ case OID_GEN_MEDIA_CAPABILITIES:
+ case OID_TCP_TASK_OFFLOAD:
+ case OID_FFP_SUPPORT:
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ // Optional stats OIDs
+
+ case OID_GEN_DIRECTED_BYTES_XMIT:
+ case OID_GEN_DIRECTED_FRAMES_XMIT:
+ case OID_GEN_MULTICAST_BYTES_XMIT:
+ case OID_GEN_MULTICAST_FRAMES_XMIT:
+ case OID_GEN_BROADCAST_BYTES_XMIT:
+ case OID_GEN_BROADCAST_FRAMES_XMIT:
+ case OID_GEN_DIRECTED_BYTES_RCV:
+ case OID_GEN_DIRECTED_FRAMES_RCV:
+ case OID_GEN_MULTICAST_BYTES_RCV:
+ case OID_GEN_MULTICAST_FRAMES_RCV:
+ case OID_GEN_BROADCAST_BYTES_RCV:
+ case OID_GEN_BROADCAST_FRAMES_RCV:
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ //===================================================================
+ // Not Handled
+ //===================================================================
+ default:
+ DEBUGP (("[%s] Unhandled OID %lx\n", NAME (l_Adapter), p_OID));
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (l_Status != NDIS_STATUS_SUCCESS)
+ ;
+ else if (l_QueryLength > p_BufferLength)
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = l_QueryLength;
+ }
+ else
+ NdisMoveMemory (p_Buffer, (PVOID) l_QueryPtr,
+ (*p_BytesWritten = l_QueryLength));
+
+ return l_Status;
+}
+
+NDIS_STATUS AdapterModify
+(IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesRead,
+ OUT PULONG p_BytesNeeded)
+{
+ TapAdapterQueryPointer l_Query = (TapAdapterQueryPointer) p_Buffer;
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ NDIS_STATUS l_Status = NDIS_STATUS_INVALID_OID;
+#ifndef VBOX
+ ULONG l_Long;
+#endif
+
+ switch (p_OID)
+ {
+ //==================================================================
+ // Device Info
+ //==================================================================
+ case OID_802_3_MULTICAST_LIST:
+ DEBUGP (("[%s] Setting [OID_802_3_MULTICAST_LIST]\n",
+ NAME (l_Adapter)));
+
+ *p_BytesNeeded = sizeof (ETH_ADDR);
+ *p_BytesRead = p_BufferLength;
+
+ if (p_BufferLength % sizeof (ETH_ADDR))
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ else if (p_BufferLength > sizeof (MC_LIST))
+ {
+ l_Status = NDIS_STATUS_MULTICAST_FULL;
+ *p_BytesNeeded = sizeof (MC_LIST);
+ }
+ else
+ {
+ NdisAcquireSpinLock (&l_Adapter->m_MCLock);
+
+ NdisZeroMemory(&l_Adapter->m_MCList, sizeof (MC_LIST));
+
+ NdisMoveMemory(&l_Adapter->m_MCList,
+ p_Buffer,
+ p_BufferLength);
+
+ l_Adapter->m_MCListSize = p_BufferLength / sizeof (ETH_ADDR);
+
+ NdisReleaseSpinLock (&l_Adapter->m_MCLock);
+
+ l_Status = NDIS_STATUS_SUCCESS;
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = 4;
+
+ if (p_BufferLength >= sizeof (ULONG))
+ {
+ DEBUGP
+ (("[%s] Setting [OID_GEN_CURRENT_PACKET_FILTER] to [0x%02lx]\n",
+ NAME (l_Adapter), l_Query->m_Long));
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = sizeof (ULONG);
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (p_BufferLength < sizeof (ULONG))
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = 4;
+ }
+ else if (l_Query->m_Long > DEFAULT_PACKET_LOOKAHEAD
+ || l_Query->m_Long <= 0)
+ {
+ l_Status = NDIS_STATUS_INVALID_DATA;
+ }
+ else
+ {
+ DEBUGP (("[%s] Setting [OID_GEN_CURRENT_LOOKAHEAD] to [%d]\n",
+ NAME (l_Adapter), l_Query->m_Long));
+ l_Adapter->m_Lookahead = l_Query->m_Long;
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = sizeof (ULONG);
+ }
+ break;
+
+ case OID_GEN_NETWORK_LAYER_ADDRESSES:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ case OID_GEN_TRANSPORT_HEADER_OFFSET:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ case OID_PNP_SET_POWER:
+ do
+ {
+ NDIS_DEVICE_POWER_STATE NewDeviceState;
+
+ NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE) p_Buffer);
+
+ switch (NewDeviceState)
+ {
+ case NdisDeviceStateD0:
+ l_Adapter->m_DeviceState = '0';
+ break;
+ case NdisDeviceStateD1:
+ l_Adapter->m_DeviceState = '1';
+ break;
+ case NdisDeviceStateD2:
+ l_Adapter->m_DeviceState = '2';
+ break;
+ case NdisDeviceStateD3:
+ l_Adapter->m_DeviceState = '3';
+ break;
+ default:
+ l_Adapter->m_DeviceState = '?';
+ break;
+ }
+
+ l_Status = NDIS_STATUS_FAILURE;
+
+ //
+ // Check for invalid length
+ //
+ if (p_BufferLength < sizeof (NDIS_DEVICE_POWER_STATE))
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (NewDeviceState > NdisDeviceStateD0)
+ {
+ l_Adapter->m_InterfaceIsRunning = FALSE;
+ DEBUGP (("[%s] Power management device state OFF\n",
+ NAME (l_Adapter)));
+ }
+ else
+ {
+ l_Adapter->m_InterfaceIsRunning = TRUE;
+ DEBUGP (("[%s] Power management device state ON\n",
+ NAME (l_Adapter)));
+ }
+
+ l_Status = NDIS_STATUS_SUCCESS;
+ }
+ while (FALSE);
+
+ if (l_Status == NDIS_STATUS_SUCCESS)
+ {
+ *p_BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *p_BytesNeeded = 0;
+ }
+ else
+ {
+ *p_BytesRead = 0;
+ *p_BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ default:
+ DEBUGP (("[%s] Can't set value for OID %lx\n", NAME (l_Adapter),
+ p_OID));
+ l_Status = NDIS_STATUS_INVALID_OID;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+ }
+
+ return l_Status;
+}
+
+//====================================================================
+// Adapter Transmission
+//====================================================================
+NDIS_STATUS
+AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
+ IN PNDIS_PACKET p_Packet,
+ IN UINT p_Flags)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ ULONG l_Index = 0, l_BufferLength = 0, l_PacketLength = 0;
+ PIRP l_IRP;
+ TapPacketPointer l_PacketBuffer;
+ PNDIS_BUFFER l_NDIS_Buffer;
+ PUCHAR l_Buffer;
+ PVOID result;
+
+ NdisQueryPacket (p_Packet, NULL, NULL, &l_NDIS_Buffer, &l_PacketLength);
+
+//// DEBUGP(("AdapterTransmit %08x size=%x\n", l_NDIS_Buffer, l_PacketLength));
+
+ //====================================================
+ // Here we abandon the transmission attempt if any of
+ // the parameters is wrong or memory allocation fails
+ // but we do not indicate failure. The packet is
+ // silently dropped.
+ //====================================================
+
+ if (l_PacketLength < ETHERNET_HEADER_SIZE || l_PacketLength > 65535)
+ goto exit_fail;
+ else if (!l_Adapter->m_Extension.m_TapOpens || !l_Adapter->m_MediaState)
+ goto exit_success; // Nothing is bound to the TAP device
+
+ if (NdisAllocateMemoryWithTag (&l_PacketBuffer,
+ TAP_PACKET_SIZE (l_PacketLength),
+ '5PAT') != NDIS_STATUS_SUCCESS)
+ goto exit_no_resources;
+
+ if (l_PacketBuffer == NULL)
+ goto exit_no_resources;
+
+ l_PacketBuffer->m_SizeFlags = (l_PacketLength & TP_SIZE_MASK);
+
+ //===========================
+ // Reassemble packet contents
+ //===========================
+
+ __try
+ {
+ for (l_Index = 0; l_NDIS_Buffer && l_Index < l_PacketLength;
+ l_Index += l_BufferLength)
+ {
+ NdisQueryBuffer (l_NDIS_Buffer, (PVOID *) & l_Buffer,
+ &l_BufferLength);
+ NdisMoveMemory (l_PacketBuffer->m_Data + l_Index, l_Buffer,
+ l_BufferLength);
+ NdisGetNextBuffer (l_NDIS_Buffer, &l_NDIS_Buffer);
+ }
+
+ DUMP_PACKET ("AdapterTransmit", l_PacketBuffer->m_Data, l_PacketLength);
+
+ //=====================================================
+ // Are we running in DHCP server masquerade mode?
+ //
+ // If so, catch both DHCP requests and ARP queries
+ // to resolve the address of our virtual DHCP server.
+ //=====================================================
+ if (l_Adapter->m_dhcp_enabled)
+ {
+ const ETH_HEADER *eth = (ETH_HEADER *) l_PacketBuffer->m_Data;
+ const IPHDR *ip = (IPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER));
+ const UDPHDR *udp = (UDPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR));
+
+ // ARP packet?
+ if (l_PacketLength == sizeof (ARP_PACKET)
+ && eth->proto == htons (ETH_P_ARP)
+ && l_Adapter->m_dhcp_server_arp)
+ {
+ if (ProcessARP (l_Adapter,
+ (PARP_PACKET) l_PacketBuffer->m_Data,
+ l_Adapter->m_dhcp_addr,
+ l_Adapter->m_dhcp_server_ip,
+ l_Adapter->m_dhcp_server_mac))
+ goto no_queue;
+ }
+
+ // DHCP packet?
+ else if (l_PacketLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP)
+ && eth->proto == htons (ETH_P_IP)
+ && ip->version_len == 0x45 // IPv4, 20 byte header
+ && ip->protocol == IPPROTO_UDP
+ && udp->dest == htons (BOOTPS_PORT))
+ {
+ const DHCP *dhcp = (DHCP *) (l_PacketBuffer->m_Data
+ + sizeof (ETH_HEADER)
+ + sizeof (IPHDR)
+ + sizeof (UDPHDR));
+
+ const int optlen = l_PacketLength
+ - sizeof (ETH_HEADER)
+ - sizeof (IPHDR)
+ - sizeof (UDPHDR)
+ - sizeof (DHCP);
+
+ if (optlen > 0) // we must have at least one DHCP option
+ {
+ if (ProcessDHCP (l_Adapter, eth, ip, udp, dhcp, optlen))
+ goto no_queue;
+ }
+ else
+ goto no_queue;
+ }
+ }
+
+ //===============================================
+ // In Point-To-Point mode, check to see whether
+ // packet is ARP or IPv4 (if neither, then drop).
+ //===============================================
+ if (l_Adapter->m_PointToPoint)
+ {
+ ETH_HEADER *e;
+
+ if (l_PacketLength < ETHERNET_HEADER_SIZE)
+ goto no_queue;
+
+ e = (ETH_HEADER *) l_PacketBuffer->m_Data;
+
+ switch (ntohs (e->proto))
+ {
+ case ETH_P_ARP:
+
+ // Make sure that packet is the
+ // right size for ARP.
+ if (l_PacketLength != sizeof (ARP_PACKET))
+ goto no_queue;
+
+ ProcessARP (l_Adapter,
+ (PARP_PACKET) l_PacketBuffer->m_Data,
+ l_Adapter->m_localIP,
+ l_Adapter->m_remoteIP,
+ l_Adapter->m_TapToUser.dest);
+
+ default:
+ goto no_queue;
+
+ case ETH_P_IP:
+
+ // Make sure that packet is large
+ // enough to be IPv4.
+ if (l_PacketLength
+ < ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)
+ goto no_queue;
+
+ // Only accept directed packets,
+ // not broadcasts.
+ if (memcmp (e, &l_Adapter->m_TapToUser, ETHERNET_HEADER_SIZE))
+ goto no_queue;
+
+ // Packet looks like IPv4, queue it.
+ l_PacketBuffer->m_SizeFlags |= TP_POINT_TO_POINT;
+ }
+ }
+
+ //===============================================
+ // Push packet onto queue to wait for read from
+ // userspace.
+ //===============================================
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ result = NULL;
+ if (IS_UP (l_Adapter))
+ result = QueuePush (l_Adapter->m_Extension.m_PacketQueue, l_PacketBuffer);
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if ((TapPacketPointer) result != l_PacketBuffer)
+ {
+ // adapter receive overrun
+ INCREMENT_STAT (l_Adapter->m_TxErr);
+ goto no_queue;
+ }
+ else
+ {
+ INCREMENT_STAT (l_Adapter->m_Tx);
+ }
+
+ //============================================================
+ // Cycle through IRPs and packets, try to satisfy each pending
+ // IRP with a queued packet.
+ //============================================================
+ while (TRUE)
+ {
+ l_IRP = NULL;
+ l_PacketBuffer = NULL;
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
+ && QueueCount (l_Adapter->m_Extension.m_IrpQueue))
+ {
+ l_IRP = (PIRP) QueuePop (l_Adapter->m_Extension.m_IrpQueue);
+ l_PacketBuffer = (TapPacketPointer)
+ QueuePop (l_Adapter->m_Extension.m_PacketQueue);
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ MYASSERT ((l_IRP != NULL) + (l_PacketBuffer != NULL) != 1);
+
+ if (l_IRP && l_PacketBuffer)
+ {
+ CompleteIRP (l_IRP,
+ l_PacketBuffer,
+ IO_NETWORK_INCREMENT);
+ }
+ else
+ break;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ no_queue:
+ NdisFreeMemory (l_PacketBuffer,
+ TAP_PACKET_SIZE (l_PacketLength),
+ 0);
+
+ exit_success:
+ return NDIS_STATUS_SUCCESS;
+
+ exit_fail:
+ return NDIS_STATUS_FAILURE;
+
+ exit_no_resources:
+ return NDIS_STATUS_RESOURCES;
+}
+
+//======================================================================
+// Hooks for catching TAP device IRP's.
+//======================================================================
+
+NTSTATUS
+TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
+{
+ TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
+ PIO_STACK_LOCATION l_IrpSp;
+ NTSTATUS l_Status = STATUS_SUCCESS;
+#ifndef VBOX
+ BOOLEAN accessible;
+#endif
+
+ l_IrpSp = IoGetCurrentIrpStackLocation (p_IRP);
+
+ p_IRP->IoStatus.Status = STATUS_SUCCESS;
+ p_IRP->IoStatus.Information = 0;
+
+ if (!l_Adapter || l_Adapter->m_Extension.m_Halt)
+ {
+ DEBUGP (("TapDeviceHook called when TAP device is halted, MajorFunction=%d\n",
+ (int)l_IrpSp->MajorFunction));
+
+ if (l_IrpSp->MajorFunction == IRP_MJ_CLOSE)
+ {
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ p_IRP->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ }
+
+ switch (l_IrpSp->MajorFunction)
+ {
+ //===========================================================
+ // Ioctl call handlers
+ //===========================================================
+ case IRP_MJ_DEVICE_CONTROL:
+ {
+ switch (l_IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case TAP_IOCTL_GET_MAC:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= sizeof (MACADDR))
+ {
+ COPY_MAC (p_IRP->AssociatedIrp.SystemBuffer,
+ l_Adapter->m_MAC);
+ p_IRP->IoStatus.Information = sizeof (MACADDR);
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+ case TAP_IOCTL_GET_VERSION:
+ {
+ const ULONG size = sizeof (ULONG) * 3;
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= size)
+ {
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
+ = TAP_DRIVER_MAJOR_VERSION;
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[1]
+ = TAP_DRIVER_MINOR_VERSION;
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[2]
+#if DBG
+ = 1;
+#else
+ = 0;
+#endif
+ p_IRP->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+ }
+ case TAP_IOCTL_GET_MTU:
+ {
+ const ULONG size = sizeof (ULONG) * 1;
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= size)
+ {
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
+ = l_Adapter->m_MTU;
+ p_IRP->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+ }
+ case TAP_IOCTL_GET_INFO:
+ {
+ char state[16];
+ if (l_Adapter->m_InterfaceIsRunning)
+ state[0] = 'A';
+ else
+ state[0] = 'a';
+ if (l_Adapter->m_Extension.m_TapIsRunning)
+ state[1] = 'T';
+ else
+ state[1] = 't';
+ state[2] = l_Adapter->m_DeviceState;
+ if (l_Adapter->m_MediaStateAlwaysConnected)
+ state[3] = 'C';
+ else
+ state[3] = 'c';
+ state[4] = '\0';
+
+ p_IRP->IoStatus.Status = l_Status = RtlStringCchPrintfExA (
+ ((LPTSTR) (p_IRP->AssociatedIrp.SystemBuffer)),
+ l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ NULL,
+ NULL,
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+ "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
+ state,
+ g_LastErrorFilename,
+ g_LastErrorLineNumber,
+ (int)l_Adapter->m_Extension.m_NumTapOpens,
+ (int)l_Adapter->m_Tx,
+ (int)l_Adapter->m_TxErr,
+ (int)l_Adapter->m_Rx,
+ (int)l_Adapter->m_RxErr,
+ (int)l_Adapter->m_Extension.m_IrpQueue->size,
+ (int)l_Adapter->m_Extension.m_IrpQueue->max_size,
+ (int)IRP_QUEUE_SIZE,
+ (int)l_Adapter->m_Extension.m_PacketQueue->size,
+ (int)l_Adapter->m_Extension.m_PacketQueue->max_size,
+ (int)PACKET_QUEUE_SIZE
+ );
+
+ p_IRP->IoStatus.Information
+ = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ break;
+ }
+
+#if DBG
+ case TAP_IOCTL_GET_LOG_LINE:
+ {
+ if (GetDebugLine ((LPTSTR)p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength))
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ else
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+
+ p_IRP->IoStatus.Information
+ = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ break;
+ }
+#endif
+
+ case TAP_IOCTL_CONFIG_POINT_TO_POINT:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 2))
+ {
+ MACADDR dest;
+
+ l_Adapter->m_PointToPoint = FALSE;
+
+ GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1);
+
+ l_Adapter->m_localIP =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_remoteIP =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+
+ COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC);
+ COPY_MAC (l_Adapter->m_TapToUser.dest, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.src, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
+
+ l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+
+ l_Adapter->m_PointToPoint = TRUE;
+
+ CheckIfDhcpAndPointToPointMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_IOCTL_SET_MEDIA_STATUS:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (ULONG) * 1))
+ {
+ ULONG parm = ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ SetMediaStatus (l_Adapter, (BOOLEAN) parm);
+ p_IRP->IoStatus.Information = 1;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ case TAP_IOCTL_CONFIG_DHCP_MASQ:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 4))
+ {
+ l_Adapter->m_dhcp_enabled = FALSE;
+ l_Adapter->m_dhcp_server_arp = FALSE;
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+ // Adapter IP addr / netmask
+ l_Adapter->m_dhcp_addr =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_dhcp_netmask =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+
+ // IP addr of DHCP masq server
+ l_Adapter->m_dhcp_server_ip =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2];
+
+ // Lease time in seconds
+ l_Adapter->m_dhcp_lease_time =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[3];
+
+ GenerateRelatedMAC (l_Adapter->m_dhcp_server_mac, l_Adapter->m_MAC, 2);
+
+ l_Adapter->m_dhcp_enabled = TRUE;
+ l_Adapter->m_dhcp_server_arp = TRUE;
+
+ CheckIfDhcpAndPointToPointMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_IOCTL_CONFIG_DHCP_SET_OPT:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength <=
+ DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE
+ && l_Adapter->m_dhcp_enabled)
+ {
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+ NdisMoveMemory (l_Adapter->m_dhcp_user_supplied_options_buffer,
+ p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len =
+ l_IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+#ifdef VBOX
+ case TAP_IOCTL_TRANSFER_ETHPACKETS:
+ {
+ PTAP_SCATTER_GATHER_LIST pList;
+ ULONG i;
+ PMDL pMdlBuf = NULL;
+
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(TAP_SCATTER_GATHER_LIST))
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ pList = (PTAP_SCATTER_GATHER_LIST)p_IRP->AssociatedIrp.SystemBuffer;
+
+ /* Sanity checks */
+ if ( pList->cPackets > TAP_SCATTER_GATHER_MAX_PACKETS
+ || l_IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(TAP_SCATTER_GATHER_LIST) + (pList->cPackets-1)*sizeof(TAP_SCATTER_GATHER_ITEM)
+ )
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ __try
+ {
+ /* Send all packets. */
+ for (i=0;i<pList->cPackets;i++)
+ {
+ char *pBuffer;
+
+ DUMP_PACKET ("IRP_MJ_WRITE ETH", (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, l_IrpSp->Parameters.Write.Length);
+
+ pMdlBuf = IoAllocateMdl(pList->aPacket[i].pPacket, pList->aPacket[i].cb, FALSE, FALSE, NULL);
+ if (!pMdlBuf)
+ {
+ p_IRP->IoStatus.Status = l_Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ /* Exceptions caught by top _try _except block */
+ /** @todo really necessary to lock the pages?? */
+ MmProbeAndLockPages(pMdlBuf, KernelMode, IoModifyAccess);
+
+ pBuffer = MmGetSystemAddressForMdlSafe(pMdlBuf, NormalPagePriority);
+ if (!pBuffer)
+ {
+ MmUnlockPages(pMdlBuf);
+ IoFreeMdl(pMdlBuf);
+ p_IRP->IoStatus.Status = l_Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ NdisMEthIndicateReceive(l_Adapter->m_MiniportAdapterHandle, (NDIS_HANDLE) l_Adapter,
+ pBuffer,
+ ETHERNET_HEADER_SIZE,
+ pBuffer + ETHERNET_HEADER_SIZE,
+ pList->aPacket[i].cb - ETHERNET_HEADER_SIZE,
+ pList->aPacket[i].cb - ETHERNET_HEADER_SIZE);
+
+ NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
+
+ MmUnlockPages(pMdlBuf);
+ IoFreeMdl(pMdlBuf);
+ pMdlBuf = NULL;
+
+ }
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ if (pMdlBuf)
+ IoFreeMdl(pMdlBuf);
+
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+ break;
+ }
+#endif
+
+ default:
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //===========================================================
+ // User mode thread issued a read request on the tap device
+ // If there are packets waiting to be read, then the request
+ // will be satisfied here. If not, then the request will be
+ // queued and satisfied by any packet that is not used to
+ // satisfy requests ahead of it.
+ //===========================================================
+ case IRP_MJ_READ:
+ {
+ TapPacketPointer l_PacketBuffer;
+ BOOLEAN pending = FALSE;
+
+ // Save IRP-accessible copy of buffer length
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Read.Length;
+
+ if (p_IRP->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ else if ((p_IRP->AssociatedIrp.SystemBuffer =
+ MmGetSystemAddressForMdlSafe
+ (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ else if (!l_Adapter->m_InterfaceIsRunning)
+ {
+ DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //==================================
+ // Can we provide immediate service?
+ //==================================
+
+ l_PacketBuffer = NULL;
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
+ && QueueCount (l_Adapter->m_Extension.m_IrpQueue) == 0)
+ {
+ l_PacketBuffer = (TapPacketPointer)
+ QueuePop (l_Adapter->m_Extension.m_PacketQueue);
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (l_PacketBuffer)
+ {
+ l_Status = CompleteIRP (p_IRP,
+ l_PacketBuffer,
+ IO_NO_INCREMENT);
+ break;
+ }
+
+ //=============================
+ // Attempt to pend read request
+ //=============================
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueuePush (l_Adapter->m_Extension.m_IrpQueue, p_IRP) == (PIRP) p_IRP)
+ {
+ IoSetCancelRoutine (p_IRP, CancelIRPCallback);
+ l_Status = STATUS_PENDING;
+ IoMarkIrpPending (p_IRP);
+ pending = TRUE;
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (pending)
+ break;
+
+ // Can't queue anymore IRP's
+ DEBUGP (("[%s] TAP [%s] read IRP overrun\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapName));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //==============================================================
+ // User mode issued a WriteFile request on the TAP file handle.
+ // The request will always get satisfied here. The call may
+ // fail if there are too many pending packets (queue full).
+ //==============================================================
+ case IRP_MJ_WRITE:
+ {
+ if (p_IRP->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if ((p_IRP->AssociatedIrp.SystemBuffer =
+ MmGetSystemAddressForMdlSafe
+ (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if (!l_Adapter->m_InterfaceIsRunning)
+ {
+ DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if (!l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ {
+ __try
+ {
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
+
+ ////DEBUGP(("IRP_MJ_WRITE %08x %x\n", p_IRP->AssociatedIrp.SystemBuffer, l_IrpSp->Parameters.Write.Length));
+
+ DUMP_PACKET ("IRP_MJ_WRITE ETH",
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length);
+
+ NdisMEthIndicateReceive
+ (l_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ ETHERNET_HEADER_SIZE,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer + ETHERNET_HEADER_SIZE,
+ l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE,
+ l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE);
+
+ NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
+
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+ else if (l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ {
+ __try
+ {
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
+
+ DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
+ &l_Adapter->m_UserToTap,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length);
+
+ NdisMEthIndicateReceive
+ (l_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ (unsigned char *) &l_Adapter->m_UserToTap,
+ sizeof (l_Adapter->m_UserToTap),
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ l_IrpSp->Parameters.Write.Length);
+
+ NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
+
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE (P2P)\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
+ NAME (l_Adapter),
+ l_IrpSp->Parameters.Write.Length));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE;
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (l_Status == STATUS_SUCCESS)
+ INCREMENT_STAT (l_Adapter->m_Rx);
+ else
+ INCREMENT_STAT (l_Adapter->m_RxErr);
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //--------------------------------------------------------------
+ // User mode thread has called CreateFile() on the tap device
+ //--------------------------------------------------------------
+ case IRP_MJ_CREATE:
+ {
+ BOOLEAN succeeded = FALSE;
+ BOOLEAN mutex_succeeded;
+
+ DEBUGP
+ (("[%s] [TAP] release [%d.%d] open request (m_TapOpens=%d)\n",
+ NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION, l_Adapter->m_Extension.m_TapOpens));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
+ if (mutex_succeeded)
+ {
+ if (l_Adapter->m_Extension.m_TapIsRunning && !l_Adapter->m_Extension.m_TapOpens)
+ {
+ ResetTapAdapterState (l_Adapter);
+ l_Adapter->m_Extension.m_TapOpens = 1;
+ succeeded = TRUE;
+ }
+
+ if (succeeded)
+ {
+ INCREMENT_STAT (l_Adapter->m_Extension.m_NumTapOpens);
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently unavailable (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //-----------------------------------------------------------
+ // User mode thread called CloseHandle() on the tap device
+ //-----------------------------------------------------------
+ case IRP_MJ_CLOSE:
+ {
+ BOOLEAN mutex_succeeded;
+
+ DEBUGP (("[%s] [TAP] release [%d.%d] close/cleanup request\n",
+ NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
+ if (mutex_succeeded)
+ {
+ l_Adapter->m_Extension.m_TapOpens = 0;
+ ResetTapAdapterState (l_Adapter);
+ FlushQueues (&l_Adapter->m_Extension);
+ SetMediaStatus (l_Adapter, FALSE);
+ RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //------------------
+ // Strange Request
+ //------------------
+ default:
+ {
+ //NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ }
+
+ return l_Status;
+}
+
+//=============================================================
+// CompleteIRP is normally called with an adapter -> userspace
+// network packet and an IRP (Pending I/O request) from userspace.
+//
+// The IRP will normally represent a queued overlapped read
+// operation from userspace that is in a wait state.
+//
+// Use the ethernet packet to satisfy the IRP.
+//=============================================================
+
+NTSTATUS
+CompleteIRP (IN PIRP p_IRP,
+ IN TapPacketPointer p_PacketBuffer,
+ IN CCHAR PriorityBoost)
+{
+ NTSTATUS l_Status = STATUS_UNSUCCESSFUL;
+
+ int offset;
+ int len;
+
+ MYASSERT (p_IRP);
+ MYASSERT (p_PacketBuffer);
+
+ IoSetCancelRoutine (p_IRP, NULL); // Disable cancel routine
+
+ //-------------------------------------------
+ // While p_PacketBuffer always contains a
+ // full ethernet packet, including the
+ // ethernet header, in point-to-point mode,
+ // we only want to return the IPv4
+ // component.
+ //-------------------------------------------
+
+ if (p_PacketBuffer->m_SizeFlags & TP_POINT_TO_POINT)
+ {
+ offset = ETHERNET_HEADER_SIZE;
+ len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
+ }
+ else
+ {
+ offset = 0;
+ len = (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK);
+ }
+
+ if (len < 0 || (int) p_IRP->IoStatus.Information < len)
+ {
+ p_IRP->IoStatus.Information = 0;
+ p_IRP->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ NOTE_ERROR ();
+ }
+ else
+ {
+ p_IRP->IoStatus.Information = len;
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+
+ __try
+ {
+ NdisMoveMemory (p_IRP->AssociatedIrp.SystemBuffer,
+ p_PacketBuffer->m_Data + offset,
+ len);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+
+ __try
+ {
+ NdisFreeMemory (p_PacketBuffer,
+ TAP_PACKET_SIZE (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK),
+ 0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+
+ if (l_Status == STATUS_SUCCESS)
+ {
+ IoCompleteRequest (p_IRP, PriorityBoost);
+ }
+ else
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+
+ return l_Status;
+}
+
+//==============================================
+// IRPs get cancelled for a number of reasons.
+//
+// The TAP device could be closed by userspace
+// when there are still pending read operations.
+//
+// The user could disable the TAP adapter in the
+// network connections control panel, while the
+// device is still open by a process.
+//==============================================
+VOID
+CancelIRPCallback (IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP)
+{
+ TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
+ CancelIRP (l_Adapter ? &l_Adapter->m_Extension : NULL, p_IRP, TRUE);
+}
+
+VOID
+CancelIRP (TapExtensionPointer p_Extension,
+ IN PIRP p_IRP,
+ BOOLEAN callback)
+{
+ BOOLEAN exists = FALSE;
+
+ MYASSERT (p_IRP);
+
+ if (p_Extension)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ exists = (QueueExtract (p_Extension->m_IrpQueue, p_IRP) == p_IRP);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ }
+ else
+ exists = TRUE;
+
+ if (exists)
+ {
+ IoSetCancelRoutine (p_IRP, NULL);
+ p_IRP->IoStatus.Status = STATUS_CANCELLED;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ if (callback)
+ IoReleaseCancelSpinLock (p_IRP->CancelIrql);
+
+ if (exists)
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+}
+
+//====================================
+// Exhaust packet and IRP queues.
+//====================================
+VOID
+FlushQueues (TapExtensionPointer p_Extension)
+{
+ PIRP l_IRP;
+ TapPacketPointer l_PacketBuffer;
+ int n_IRP=0, n_Packet=0;
+
+ MYASSERT (p_Extension);
+ MYASSERT (p_Extension->m_TapDevice);
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ l_IRP = QueuePop (p_Extension->m_IrpQueue);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ if (l_IRP)
+ {
+ ++n_IRP;
+ CancelIRP (NULL, l_IRP, FALSE);
+ }
+ else
+ break;
+ }
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ l_PacketBuffer = QueuePop (p_Extension->m_PacketQueue);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ if (l_PacketBuffer)
+ {
+ ++n_Packet;
+ MemFree (l_PacketBuffer, TAP_PACKET_SIZE (l_PacketBuffer->m_SizeFlags & TP_SIZE_MASK));
+ }
+ else
+ break;
+ }
+
+ DEBUGP ((
+ "[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d]\n",
+ p_Extension->m_TapName,
+ n_IRP,
+ p_Extension->m_IrpQueue->max_size,
+ IRP_QUEUE_SIZE,
+ n_Packet,
+ p_Extension->m_PacketQueue->max_size,
+ PACKET_QUEUE_SIZE
+ ));
+}
+
+//===================================================
+// Tell Windows whether the TAP device should be
+// considered "connected" or "disconnected".
+//===================================================
+VOID
+SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state)
+{
+ if (p_Adapter->m_MediaState != state && !p_Adapter->m_MediaStateAlwaysConnected)
+ {
+ if (state)
+ NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
+ NDIS_STATUS_MEDIA_CONNECT, NULL, 0);
+ else
+ NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0);
+
+ NdisMIndicateStatusComplete (p_Adapter->m_MiniportAdapterHandle);
+ p_Adapter->m_MediaState = state;
+ }
+}
+
+
+//======================================================
+// If DHCP mode is used together with Point-to-point
+// mode, consider the fact that the P2P remote endpoint
+// might be equal to the DHCP masq server address.
+//======================================================
+VOID
+CheckIfDhcpAndPointToPointMode (TapAdapterPointer p_Adapter)
+{
+ if (p_Adapter->m_PointToPoint && p_Adapter->m_dhcp_enabled)
+ {
+ if (p_Adapter->m_dhcp_server_ip == p_Adapter->m_remoteIP)
+ {
+ COPY_MAC (p_Adapter->m_dhcp_server_mac, p_Adapter->m_TapToUser.dest);
+ p_Adapter->m_dhcp_server_arp = FALSE;
+ }
+ }
+}
+
+//===================================================
+// Generate an ARP reply message for specific kinds
+// ARP queries.
+//===================================================
+BOOLEAN
+ProcessARP (TapAdapterPointer p_Adapter,
+ const PARP_PACKET src,
+ const IPADDR adapter_ip,
+ const IPADDR ip,
+ const MACADDR mac)
+{
+ //-----------------------------------------------
+ // Is this the kind of packet we are looking for?
+ //-----------------------------------------------
+ if (src->m_Proto == htons (ETH_P_ARP)
+ && MAC_EQUAL (src->m_MAC_Source, p_Adapter->m_MAC)
+ && MAC_EQUAL (src->m_ARP_MAC_Source, p_Adapter->m_MAC)
+ && MAC_EQUAL (src->m_MAC_Destination, p_Adapter->m_MAC_Broadcast)
+ && src->m_ARP_Operation == htons (ARP_REQUEST)
+ && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE)
+ && src->m_MAC_AddressSize == sizeof (MACADDR)
+ && src->m_PROTO_AddressType == htons (ETH_P_IP)
+ && src->m_PROTO_AddressSize == sizeof (IPADDR)
+ && src->m_ARP_IP_Source == adapter_ip
+ && src->m_ARP_IP_Destination == ip)
+ {
+ ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE);
+ if (arp)
+ {
+ //----------------------------------------------
+ // Initialize ARP reply fields
+ //----------------------------------------------
+ arp->m_Proto = htons (ETH_P_ARP);
+ arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE);
+ arp->m_PROTO_AddressType = htons (ETH_P_IP);
+ arp->m_MAC_AddressSize = sizeof (MACADDR);
+ arp->m_PROTO_AddressSize = sizeof (IPADDR);
+ arp->m_ARP_Operation = htons (ARP_REPLY);
+
+ //----------------------------------------------
+ // ARP addresses
+ //----------------------------------------------
+ COPY_MAC (arp->m_MAC_Source, mac);
+ COPY_MAC (arp->m_MAC_Destination, p_Adapter->m_MAC);
+ COPY_MAC (arp->m_ARP_MAC_Source, mac);
+ COPY_MAC (arp->m_ARP_MAC_Destination, p_Adapter->m_MAC);
+ arp->m_ARP_IP_Source = ip;
+ arp->m_ARP_IP_Destination = adapter_ip;
+
+ DUMP_PACKET ("ProcessARP",
+ (unsigned char *) arp,
+ sizeof (ARP_PACKET));
+
+ InjectPacket (p_Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
+
+ MemFree (arp, sizeof (ARP_PACKET));
+ }
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+//===============================================================
+// Used in cases where internally generated packets such as
+// ARP or DHCP replies must be returned to the kernel, to be
+// seen as an incoming packet "arriving" on the interface.
+//===============================================================
+
+VOID
+InjectPacket (TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len)
+{
+ MYASSERT (len >= ETHERNET_HEADER_SIZE);
+
+ __try
+ {
+ //------------------------------------------------------------
+ // NdisMEthIndicateReceive and NdisMEthIndicateReceiveComplete
+ // could potentially be called reentrantly both here and in
+ // TapDeviceHook/IRP_MJ_WRITE.
+ //
+ // The DDK docs imply that this is okay.
+ //------------------------------------------------------------
+ NdisMEthIndicateReceive
+ (p_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) p_Adapter,
+ packet,
+ ETHERNET_HEADER_SIZE,
+ packet + ETHERNET_HEADER_SIZE,
+ len - ETHERNET_HEADER_SIZE,
+ len - ETHERNET_HEADER_SIZE);
+
+ NdisMEthIndicateReceiveComplete (p_Adapter->m_MiniportAdapterHandle);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacket\n",
+ NAME (p_Adapter)));
+ NOTE_ERROR ();
+ }
+}
+
+//===================================================================
+// Go back to default TAP mode from Point-To-Point mode.
+// Also reset (i.e. disable) DHCP Masq mode.
+//===================================================================
+VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
+{
+ // Point-To-Point
+ p_Adapter->m_PointToPoint = FALSE;
+ p_Adapter->m_localIP = 0;
+ p_Adapter->m_remoteIP = 0;
+ NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
+ NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
+
+ // DHCP Masq
+ p_Adapter->m_dhcp_enabled = FALSE;
+ p_Adapter->m_dhcp_server_arp = FALSE;
+ p_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+ p_Adapter->m_dhcp_addr = 0;
+ p_Adapter->m_dhcp_netmask = 0;
+ p_Adapter->m_dhcp_server_ip = 0;
+ p_Adapter->m_dhcp_lease_time = 0;
+ p_Adapter->m_dhcp_received_discover = FALSE;
+ p_Adapter->m_dhcp_bad_requests = 0;
+ NdisZeroMemory (p_Adapter->m_dhcp_server_mac, sizeof (MACADDR));
+}
+
+#if ENABLE_NONADMIN
+
+//===================================================================
+// Set TAP device handle to be accessible without admin privileges.
+//===================================================================
+VOID AllowNonAdmin (TapExtensionPointer p_Extension)
+{
+ NTSTATUS stat;
+ SECURITY_DESCRIPTOR sd;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK isb;
+ HANDLE hand = NULL;
+
+ NdisZeroMemory (&sd, sizeof (sd));
+ NdisZeroMemory (&oa, sizeof (oa));
+ NdisZeroMemory (&isb, sizeof (isb));
+
+ if (!p_Extension->m_CreatedUnicodeLinkName)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: UnicodeLinkName is uninitialized\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: RtlCreateSecurityDescriptor failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ InitializeObjectAttributes (
+ &oa,
+ &p_Extension->m_UnicodeLinkName,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ stat = ZwOpenFile (
+ &hand,
+ WRITE_DAC,
+ &oa,
+ &isb,
+ 0,
+ 0
+ );
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwOpenFile failed, status=0x%08x\n", (unsigned int)stat));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwSetSecurityObject (hand, DACL_SECURITY_INFORMATION, &sd);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwSetSecurityObject failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwClose (hand);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwClose failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ DEBUGP (("[TAP] AllowNonAdmin: SUCCEEDED\n"));
+}
+
+#endif
+
+//======================================================================
+// End of Source
+//======================================================================
diff --git a/src/VBox/HostDrivers/VBoxTAP/types.h b/src/VBox/HostDrivers/VBoxTAP/types.h
new file mode 100644
index 000000000..a82ad2b4f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxTAP/types.h
@@ -0,0 +1,163 @@
+/*
+ * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
+ * on Windows. Originally derived from the CIPE-Win32
+ * project by Damion K. Wilson, with extensive modifications by
+ * James Yonan.
+ *
+ * All source code which derives from the CIPE-Win32 project is
+ * Copyright (C) Damion K. Wilson, 2003, and is released under the
+ * GPL version 2 (see below).
+ *
+ * All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TAP_TYPES_DEFINED
+#define TAP_TYPES_DEFINED
+
+typedef struct _Queue
+{
+ ULONG base;
+ ULONG size;
+ ULONG capacity;
+ ULONG max_size;
+ PVOID data[];
+} Queue;
+
+typedef struct _TapAdapter;
+typedef struct _TapPacket;
+
+typedef union _TapAdapterQuery
+{
+ NDIS_HARDWARE_STATUS m_HardwareStatus;
+ NDIS_MEDIUM m_Medium;
+ NDIS_PHYSICAL_MEDIUM m_PhysicalMedium;
+ UCHAR m_MacAddress [6];
+ UCHAR m_Buffer [256];
+ ULONG m_Long;
+ USHORT m_Short;
+ UCHAR m_Byte;
+}
+TapAdapterQuery, *TapAdapterQueryPointer;
+
+typedef struct _TapExtension
+{
+ // TAP device object and packet queues
+ Queue *m_PacketQueue, *m_IrpQueue;
+ PDEVICE_OBJECT m_TapDevice;
+ NDIS_HANDLE m_TapDeviceHandle;
+ ULONG m_TapOpens;
+
+ // Used to lock packet queues
+ NDIS_SPIN_LOCK m_QueueLock;
+ BOOLEAN m_AllocatedSpinlocks;
+
+ // Used to bracket open/close
+ // state changes.
+ MUTEX m_OpenCloseMutex;
+
+ // True if device has been permanently halted
+ BOOLEAN m_Halt;
+
+ // TAP device name
+ unsigned char *m_TapName;
+ UNICODE_STRING m_UnicodeLinkName;
+ BOOLEAN m_CreatedUnicodeLinkName;
+
+ // Used for device status ioctl only
+ const char *m_LastErrorFilename;
+ int m_LastErrorLineNumber;
+ LONG m_NumTapOpens;
+
+ // Flags
+ BOOLEAN m_TapIsRunning;
+ BOOLEAN m_CalledTapDeviceFreeResources;
+}
+TapExtension, *TapExtensionPointer;
+
+typedef struct _TapPacket
+ {
+# define TAP_PACKET_SIZE(data_size) (sizeof (TapPacket) + (data_size))
+# define TP_POINT_TO_POINT 0x80000000
+# define TP_SIZE_MASK (~TP_POINT_TO_POINT)
+ ULONG m_SizeFlags;
+ UCHAR m_Data []; // m_Data must be the last struct member
+ }
+TapPacket, *TapPacketPointer;
+
+typedef struct _TapAdapter
+{
+# define NAME(a) ((a)->m_NameAnsi.Buffer)
+ ANSI_STRING m_NameAnsi;
+ MACADDR m_MAC;
+ BOOLEAN m_InterfaceIsRunning;
+ NDIS_HANDLE m_MiniportAdapterHandle;
+ LONG m_Rx, m_Tx, m_RxErr, m_TxErr;
+ NDIS_MEDIUM m_Medium;
+ ULONG m_Lookahead;
+ ULONG m_MTU;
+
+ // TRUE if adapter should always be
+ // "connected" even when device node
+ // is not open by a userspace process.
+ BOOLEAN m_MediaStateAlwaysConnected;
+
+ // TRUE if device is "connected"
+ BOOLEAN m_MediaState;
+
+ // Adapter power state
+ char m_DeviceState;
+
+ // Info for point-to-point mode
+ BOOLEAN m_PointToPoint;
+ IPADDR m_localIP;
+ IPADDR m_remoteIP;
+ ETH_HEADER m_TapToUser;
+ ETH_HEADER m_UserToTap;
+ MACADDR m_MAC_Broadcast;
+
+ // Used for DHCP server masquerade
+ BOOLEAN m_dhcp_enabled;
+ IPADDR m_dhcp_addr;
+ ULONG m_dhcp_netmask;
+ IPADDR m_dhcp_server_ip;
+ BOOLEAN m_dhcp_server_arp;
+ MACADDR m_dhcp_server_mac;
+ ULONG m_dhcp_lease_time;
+ UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE];
+ ULONG m_dhcp_user_supplied_options_buffer_len;
+ BOOLEAN m_dhcp_received_discover;
+ ULONG m_dhcp_bad_requests;
+
+ // Help to tear down the adapter by keeping
+ // some state information on allocated
+ // resources.
+ BOOLEAN m_CalledAdapterFreeResources;
+ BOOLEAN m_RegisteredAdapterShutdownHandler;
+
+ // Multicast list info
+ NDIS_SPIN_LOCK m_MCLock;
+ BOOLEAN m_MCLockAllocated;
+ ULONG m_MCListSize;
+ MC_LIST m_MCList;
+
+ // Information on the TAP device
+ TapExtension m_Extension;
+} TapAdapter, *TapAdapterPointer;
+
+#endif
+
diff --git a/src/VBox/HostDrivers/linux/Makefile b/src/VBox/HostDrivers/linux/Makefile
new file mode 100644
index 000000000..ea79be321
--- /dev/null
+++ b/src/VBox/HostDrivers/linux/Makefile
@@ -0,0 +1,64 @@
+#
+# Makefile for the VirtualBox Linux Host Drivers.
+#
+
+#
+#
+# Copyright (C) 2008-2009 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+KBUILD_VERBOSE =
+
+all:
+ @echo "*** Building 'vboxdrv' module ***"
+ @$(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C vboxdrv
+ @cp vboxdrv/vboxdrv.ko .
+ @echo
+ @if [ -d vboxnetflt ]; then \
+ if [ -f vboxdrv/Module.symvers ]; then \
+ cp vboxdrv/Module.symvers vboxnetflt; \
+ fi; \
+ echo "*** Building 'vboxnetflt' module ***"; \
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C vboxnetflt; \
+ cp vboxnetflt/vboxnetflt.ko .; \
+ fi
+
+
+install:
+ @$(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C vboxdrv install
+ @if [ -d vboxnetflt ]; then \
+ $(MAKE) KBUILD_VERBOSE=$(KBUILD_VERBOSE) -C vboxnetflt install; \
+ fi
+
+clean:
+ @$(MAKE) -C vboxdrv clean
+ @if [ -d vboxnetflt ]; then \
+ $(MAKE) -C vboxnetflt clean; \
+ fi
+ rm -f vboxdrv.ko vboxnetflt.ko
+
+load:
+ @for module in vboxnetflt vboxdrv; do \
+ if grep "^$$module " /proc/modules >/dev/null; then \
+ echo "Removing previously installed $$module module"; \
+ /sbin/rmmod $$module; \
+ fi; \
+ done
+ @for module in vboxdrv vboxnetflt; do \
+ if test -f $$module.ko; then \
+ echo "Installing $$module module"; \
+ /sbin/insmod $$module.ko; \
+ fi; \
+ done
diff --git a/src/VBox/HostDrivers/linux/Makefile.kup b/src/VBox/HostDrivers/linux/Makefile.kup
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/VBox/HostDrivers/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/linux/build_in_tmp b/src/VBox/HostDrivers/linux/build_in_tmp
new file mode 100755
index 000000000..0b1d17a5a
--- /dev/null
+++ b/src/VBox/HostDrivers/linux/build_in_tmp
@@ -0,0 +1,112 @@
+#!/bin/sh
+
+#
+# Script to build a kernel module in /tmp. Useful if the module sources
+# are installed in read-only directory.
+#
+# Copyright (C) 2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+# Attempt to build using DKMS first
+DKMS=`which dkms 2>/dev/null`
+if [ -n "$DKMS" ]
+then
+ echo "Attempting to install using DKMS"
+ $DKMS status -m _MODULE_ | while read line
+ # first, remove _any_ old module
+ do
+ if echo "$line" | grep -q added > /dev/null ||
+ echo "$line" | grep -q built > /dev/null ||
+ echo "$line" | grep -q installed > /dev/null; then
+ version=`echo "$line" | sed "s/_MODULE_,\([^,]*\),.*/\1/;t;d"`
+ echo " removing old DKMS module _MODULE_ version $version"
+ $DKMS remove -m _MODULE_ -v $version --all
+ fi
+ done
+ # there should not be any more matches
+ status=`$DKMS status -m _MODULE_ -v _VERSION_`
+ if echo $status | grep added > /dev/null ||
+ echo $status | grep built > /dev/null ||
+ echo $status | grep installed > /dev/null
+ then
+ $DKMS remove -m _MODULE_ -v _VERSION_ --all
+ fi
+ # finally install the module
+ if $DKMS add -m _MODULE_ -v _VERSION_ &&
+ $DKMS build -m _MODULE_ -v _VERSION_ &&
+ $DKMS install -m _MODULE_ -v _VERSION_ --force
+ then
+ exit 0
+ fi
+ echo "Failed to install using DKMS, attempting to install without"
+fi
+
+# find a unique temp directory
+num=0
+while true; do
+ tmpdir="/tmp/vbox.$num"
+ if mkdir -m 0755 "$tmpdir" 2> /dev/null; then
+ break
+ fi
+ num=`expr $num + 1`
+ if [ $num -gt 200 ]; then
+ echo "Could not find a valid tmp directory"
+ exit 1
+ fi
+done
+
+if [ "$1" = "--save-module-symvers" ]; then
+ shift
+ SAVE_MOD_SYMVERS="$1"
+ shift
+fi
+
+if [ "$1" = "--use-module-symvers" ]; then
+ shift
+ USE_MOD_SYMVERS="$1"
+ shift
+fi
+
+# copy
+cp -a ${0%/*}/* $tmpdir/
+if [ -n "$USE_MOD_SYMVERS" ]; then
+ cp $USE_MOD_SYMVERS $tmpdir/Module.symvers
+fi
+
+# make, cleanup if success
+cd "$tmpdir"
+if make "$@"; then
+ if [ -n "$SAVE_MOD_SYMVERS" ]; then
+ if [ -f Module.symvers ]; then
+ cp -f Module.symvers $SAVE_MOD_SYMVERS
+ else
+ cat /dev/null > $SAVE_MOD_SYMVERS
+ fi
+ fi
+ rm -rf $tmpdir
+ exit 0
+fi
+
+# failure
+exit 1
diff --git a/src/VBox/HostDrivers/linux/export_modules b/src/VBox/HostDrivers/linux/export_modules
new file mode 100755
index 000000000..a0dca9902
--- /dev/null
+++ b/src/VBox/HostDrivers/linux/export_modules
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+#
+# Create a tar archive containing the sources of the vboxdrv kernel module
+#
+# Copyright (C) 2007 Sun Microsystems, Inc.
+#
+# 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.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+# Clara, CA 95054 USA or visit http://www.sun.com if you need
+# additional information or have any questions.
+#
+
+if [ -z "$1" ]; then
+ echo "Usage: $0 <filename.tar.gz> [--without-hardening]"
+ echo " Export VirtualBox kernel modules to <filename.tar.gz>"
+ exit 1
+fi
+
+VBOX_WITH_HARDENING=1
+if [ "$2" = "--without-hardening" ]; then
+ VBOX_WITH_HARDENING=
+fi
+
+PATH_TMP="`cd \`dirname $1\`; pwd`/.vbox_modules"
+PATH_OUT=$PATH_TMP
+FILE_OUT="`cd \`dirname $1\`; pwd`/`basename $1`"
+PATH_ROOT="`cd \`dirname $0\`/../../../..; pwd`"
+PATH_LINUX="$PATH_ROOT/src/VBox/HostDrivers/linux"
+PATH_VBOXDRV="$PATH_ROOT/src/VBox/HostDrivers/Support"
+PATH_VBOXNET="$PATH_ROOT/src/VBox/HostDrivers/VBoxNetFlt"
+
+VBOX_VERSION_MAJOR=`sed -e "s/^ *VBOX_VERSION_MAJOR *= \+\([0-9]\+\)/\1/;t;d" $PATH_ROOT/Config.kmk`
+VBOX_VERSION_MINOR=`sed -e "s/^ *VBOX_VERSION_MINOR *= \+\([0-9]\+\)/\1/;t;d" $PATH_ROOT/Config.kmk`
+VBOX_VERSION_BUILD=`sed -e "s/^ *VBOX_VERSION_BUILD *= \+\([0-9]\+\)/\1/;t;d" $PATH_ROOT/Config.kmk`
+VBOX_VERSION_STRING=$VBOX_VERSION_MAJOR.$VBOX_VERSION_MINOR.$VBOX_VERSION_BUILD
+
+. $PATH_VBOXDRV/linux/files_vboxdrv
+. $PATH_VBOXNET/linux/files_vboxnetflt
+
+# Temporary path for creating the modules, will be removed later
+mkdir $PATH_TMP || exit 1
+
+# Create auto-generated version file, needed by all modules
+echo "#ifndef __version_generated_h__" > $PATH_TMP/version-generated.h
+echo "#define __version_generated_h__" >> $PATH_TMP/version-generated.h
+echo "" >> $PATH_TMP/version-generated.h
+echo "#define VBOX_VERSION_MAJOR $VBOX_VERSION_MAJOR" >> $PATH_TMP/version-generated.h
+echo "#define VBOX_VERSION_MINOR $VBOX_VERSION_MINOR" >> $PATH_TMP/version-generated.h
+echo "#define VBOX_VERSION_BUILD $VBOX_VERSION_BUILD" >> $PATH_TMP/version-generated.h
+echo "#define VBOX_VERSION_STRING \"$VBOX_VERSION_STRING\"" >> $PATH_TMP/version-generated.h
+echo "" >> $PATH_TMP/version-generated.h
+echo "#endif" >> $PATH_TMP/version-generated.h
+
+# vboxdrv (VirtualBox host kernel module)
+mkdir $PATH_TMP/vboxdrv || exit 1
+for f in $FILES_VBOXDRV_NOBIN; do
+ install -D -m 0644 `echo $f|cut -d'=' -f1` "$PATH_TMP/vboxdrv/`echo $f|cut -d'>' -f2`"
+done
+for f in $FILES_VBOXDRV_BIN; do
+ install -D -m 0755 `echo $f|cut -d'=' -f1` "$PATH_TMP/vboxdrv/`echo $f|cut -d'>' -f2`"
+done
+sed -e "s;_VERSION_;$VBOX_VERSION_STRING;g" < $PATH_LINUX/build_in_tmp > $PATH_TMP/vboxdrv/build_in_tmp
+chmod 0755 $PATH_TMP/vboxdrv/build_in_tmp
+sed -e "s;_VERSION_;$VBOX_VERSION_STRING;g" < $PATH_VBOXDRV/linux/dkms.conf > $PATH_TMP/vboxdrv/dkms.conf
+if [ -n "$VBOX_WITH_HARDENING" ]; then
+ cat $PATH_VBOXDRV/linux/Makefile > $PATH_TMP/vboxdrv/Makefile
+else
+ sed -e "s;-DVBOX_WITH_HARDENING;;g" < $PATH_VBOXDRV/linux/Makefile > $PATH_TMP/vboxdrv/Makefile
+fi
+
+# vboxnetflt (VirtualBox netfilter kernel module)
+mkdir $PATH_TMP/vboxnetflt || exit 1
+for f in $VBOX_VBOXNETFLT_SOURCES; do
+ install -D -m 0644 `echo $f|cut -d'=' -f1` "$PATH_TMP/vboxnetflt/`echo $f|cut -d'>' -f2`"
+done
+sed -e "s;_VERSION_;$VBOX_VERSION_STRING;g" < $PATH_LINUX/build_in_tmp > $PATH_TMP/vboxnetflt/build_in_tmp
+chmod 0755 $PATH_TMP/vboxnetflt/build_in_tmp
+sed -e "s;_VERSION_;$VBOX_VERSION_STRING;g" < $PATH_VBOXNET/linux/dkms.conf > $PATH_TMP/vboxnetflt/dkms.conf
+if [ -n "$VBOX_WITH_HARDENING" ]; then
+ cat $PATH_VBOXNET/linux/Makefile > $PATH_TMP/vboxnetflt/Makefile
+else
+ sed -e "s;-DVBOX_WITH_HARDENING;;g" < $PATH_VBOXNET/linux/Makefile > $PATH_TMP/vboxnetflt/Makefile
+fi
+
+install -D -m 0644 $PATH_LINUX/Makefile $PATH_TMP/Makefile
+
+# Only temporary, omit from archive
+rm $PATH_TMP/version-generated.h
+
+# Create the archive
+tar -czf $FILE_OUT -C $PATH_TMP . || exit 1
+
+# Remove the temporary directory
+rm -r $PATH_TMP
+