[Pkg-virtualbox-commits] [virtualbox] 01/01: Imported Upstream version 4.3.32-dfsg
Gianfranco Costamagna
locutusofborg-guest at moszumanska.debian.org
Mon Oct 26 10:44:51 UTC 2015
This is an automated email from the git hooks/post-receive script.
locutusofborg-guest pushed a commit to annotated tag upstream/4.3.32-dfsg
in repository virtualbox.
commit 456e39d3b81bed910196649fec5c6ca8a5ac1b0f
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Mon Oct 26 11:29:21 2015 +0100
Imported Upstream version 4.3.32-dfsg
---
Config.kmk | 14 +-
doc/manual/en_US/user_BasicConcepts.xml | 3 +-
doc/manual/en_US/user_GuestAdditions.xml | 14 +-
doc/manual/en_US/user_Security.xml | 13 +-
doc/manual/en_US/user_Storage.xml | 12 +-
doc/manual/en_US/user_Troubleshooting.xml | 20 +
doc/manual/en_US/user_VBoxManage.xml | 4 +-
doc/manual/user_ChangeLogImpl.xml | 92 +
include/VBox/err.h | 4 +
include/VBox/sup.h | 26 +-
include/VBox/vmm/pdmifs.h | 13 +-
include/iprt/asm-amd64-x86.h | 178 ++
include/iprt/asm.h | 2 +-
include/iprt/asn1.h | 6 +-
include/iprt/cdefs.h | 1 +
include/iprt/crypto/digest.h | 4 +-
include/iprt/crypto/pem.h | 36 +-
include/iprt/crypto/store.h | 240 ++
include/iprt/crypto/x509.h | 2 +-
include/iprt/dir.h | 2 +-
include/iprt/err.h | 52 +-
include/iprt/file.h | 14 +
include/iprt/fs.h | 13 +
include/iprt/http.h | 162 +-
include/iprt/log.h | 6 +-
include/iprt/mangling.h | 41 +-
include/iprt/mp.h | 46 +
include/iprt/path.h | 83 +-
include/iprt/sha.h | 45 +
include/iprt/string.h | 25 +
include/iprt/types.h | 15 +
include/iprt/uri.h | 246 +-
.../Additions/common/VBoxGuest/VBoxGuest-solaris.c | 8 +-
.../common/VBoxService/VBoxServiceVMInfo.cpp | 53 +-
src/VBox/Additions/common/crOpenGL/DD_glc.py | 0
src/VBox/Additions/common/crOpenGL/DD_glh.py | 0
src/VBox/Additions/common/crOpenGL/NULLfuncs.py | 0
src/VBox/Additions/common/crOpenGL/cr_gl.py | 0
src/VBox/Additions/common/crOpenGL/entrypoints.py | 0
.../Additions/common/crOpenGL/feedback/feedback.py | 0
.../common/crOpenGL/feedback/feedback_funcs.py | 0
.../common/crOpenGL/feedback/feedback_state.py | 0
.../common/crOpenGL/feedback/feedbackspu_proto.py | 0
.../Additions/common/crOpenGL/getprocaddress.py | 0
src/VBox/Additions/common/crOpenGL/pack/pack.py | 0
.../common/crOpenGL/pack/packspu_beginend.py | 0
.../common/crOpenGL/pack/packspu_flush.py | 0
.../common/crOpenGL/pack/packspu_proto.py | 0
.../common/crOpenGL/passthrough/passthrough.py | 0
src/VBox/Additions/common/crOpenGL/tsfuncs.py | 0
.../common/crOpenGL/windows_getprocaddress.py | 0
src/VBox/Additions/linux/installer/vboxadd.sh | 8 +-
src/VBox/Additions/linux/sharedfolders/dirops.c | 34 +-
src/VBox/Additions/linux/sharedfolders/lnkops.c | 14 +
src/VBox/Additions/solaris/DRM/vboxvideo_drm.c | 3 +-
src/VBox/Additions/solaris/Mouse/vboxms.c | 3 +-
src/VBox/Additions/x11/vboxvideo/vboxvideo.c | 13 +-
src/VBox/Debugger/DBGCTcp.cpp | 4 +-
src/VBox/Debugger/DBGConsole.cpp | 12 +-
.../BaseTools/Source/Python/BPDG/StringTable.py | 0
.../Source/Python/Common/FdfParserLite.py | 0
.../Source/Python/Common/Identification.py | 0
.../BaseTools/Source/Python/Common/VpdInfoFile.py | 0
.../Source/Python/CommonDataClass/CommonClass.py | 0
.../Source/Python/CommonDataClass/FdfClass.py | 0
.../BaseTools/Source/Python/Ecc/CodeFragment.py | 0
.../BaseTools/Source/Python/Ecc/ParserWarning.py | 0
.../BaseTools/Source/Python/Ecc/Xml/XmlRoutines.py | 0
.../BaseTools/Source/Python/Ecc/Xml/__init__.py | 0
.../BaseTools/Source/Python/Eot/CodeFragment.py | 0
.../BaseTools/Source/Python/Eot/ParserWarning.py | 0
.../Firmware/BaseTools/Source/Python/Eot/Report.py | 0
.../BaseTools/Source/Python/GenFds/Attribute.py | 0
.../BaseTools/Source/Python/Table/Table.py | 0
.../BaseTools/Source/Python/UPT/BuildVersion.py | 0
.../BaseTools/Source/Python/UPT/Core/__init__.py | 0
.../Source/Python/UPT/GenMetaFile/GenXmlFile.py | 0
.../Source/Python/UPT/GenMetaFile/__init__.py | 0
.../Source/Python/UPT/Library/DataType.py | 0
.../Source/Python/UPT/Library/GlobalData.py | 0
.../Source/Python/UPT/Library/Xml/__init__.py | 0
.../Source/Python/UPT/Library/__init__.py | 0
.../Source/Python/UPT/Logger/StringTable.py | 0
.../BaseTools/Source/Python/UPT/Logger/__init__.py | 0
.../Source/Python/UPT/Object/POM/__init__.py | 0
.../Python/UPT/Object/Parser/InfCommonObject.py | 0
.../Python/UPT/Object/Parser/InfHeaderObject.py | 0
.../Source/Python/UPT/Object/Parser/__init__.py | 0
.../BaseTools/Source/Python/UPT/Object/__init__.py | 0
.../BaseTools/Source/Python/UPT/Parser/__init__.py | 0
.../Source/Python/UPT/PomAdapter/__init__.py | 0
.../BaseTools/Source/Python/UPT/Xml/__init__.py | 0
.../Firmware/UefiCpuPkg/ResetVector/Vtf0/Build.py | 0
.../ResetVector/Vtf0/Tools/FixupForRawSection.py | 0
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd | Bin 1048576 -> 1048576 bytes
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd | Bin 1048576 -> 1048576 bytes
.../Graphics/BIOS/VBoxVgaBiosAlternative.asm | 6 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative.md5sum | 2 +-
src/VBox/Devices/Graphics/DevVGA-SVGA.cpp | 799 ++++--
src/VBox/Devices/Graphics/DevVGA-SVGA.h | 9 +-
src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.h | 7 +-
src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m | 527 +++-
src/VBox/Devices/Graphics/DevVGA-SVGA3d-info.cpp | 1953 ++++++++++++++
src/VBox/Devices/Graphics/DevVGA-SVGA3d-internal.h | 1062 ++++++++
src/VBox/Devices/Graphics/DevVGA-SVGA3d-ogl.cpp | 2725 ++++++--------------
...VGA3d-shared.h => DevVGA-SVGA3d-savedstate.cpp} | 446 ++--
src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.cpp | 202 +-
src/VBox/Devices/Graphics/DevVGA-SVGA3d-win.cpp | 1654 ++++--------
src/VBox/Devices/Graphics/DevVGA-SVGA3d.cpp | 568 ++++
src/VBox/Devices/Graphics/DevVGA-SVGA3d.h | 144 +-
src/VBox/Devices/Graphics/DevVGA.cpp | 14 +-
src/VBox/Devices/Graphics/DevVGA.h | 64 +-
src/VBox/Devices/Graphics/DevVGA_VBVA.cpp | 2 +-
src/VBox/Devices/Graphics/VBoxSVGA3D.def | 2 +-
src/VBox/Devices/Graphics/VBoxSVGA3DObjC.def | 14 +-
src/VBox/Devices/Graphics/testcase/dump-vmwgfx.c | 34 +-
src/VBox/Devices/Makefile.kmk | 14 +-
src/VBox/Devices/Network/SrvIntNetR0.cpp | 16 +-
src/VBox/Devices/Network/slirp/slirp.c | 3 +
src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative.md5sum | 2 +-
src/VBox/Devices/Storage/DevATA.cpp | 110 +-
src/VBox/Devices/VMMDev/VMMDev.cpp | 76 +-
.../Devices/testcase/tstDeviceStructSizeRC.cpp | 2 +-
src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp | 267 +-
src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp | 4 +-
src/VBox/Frontends/VirtualBox/Makefile.kmk | 63 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts | 1842 +++----------
src/VBox/Frontends/VirtualBox/src/main.cpp | 80 +-
.../VirtualBox/src/net/UINetworkReply.cpp | 1026 ++++----
.../VirtualBox/src/net/UINetworkRequestWidget.cpp | 4 +
.../VirtualBox/src/net/tstSSLCertDownloads.cpp | 165 ++
.../VirtualBox/src/widgets/UIFilmContainer.cpp | 0
src/VBox/GuestHost/OpenGL/error/error.py | 0
src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py | 0
src/VBox/GuestHost/OpenGL/packer/pack_header.py | 0
src/VBox/GuestHost/OpenGL/packer/packer_bbox.py | 0
src/VBox/GuestHost/OpenGL/spu_loader/dispatch.py | 0
.../GuestHost/OpenGL/spu_loader/dispatchheader.py | 0
src/VBox/GuestHost/OpenGL/spu_loader/glloader.py | 0
src/VBox/GuestHost/OpenGL/spu_loader/spuchange.py | 0
src/VBox/GuestHost/OpenGL/spu_loader/spucopy.py | 0
.../GuestHost/OpenGL/state_tracker/state_defs.py | 0
.../GuestHost/OpenGL/state_tracker/state_funcs.py | 0
.../GuestHost/OpenGL/state_tracker/state_glsl.c | 9 +-
.../OpenGL/state_tracker/state_isenabled.py | 0
src/VBox/GuestHost/OpenGL/util/debug_opcodes.py | 0
src/VBox/HostDrivers/Support/Makefile.kmk | 13 +-
src/VBox/HostDrivers/Support/SUPDrv.c | 105 +
src/VBox/HostDrivers/Support/SUPDrvIOC.h | 4 +-
src/VBox/HostDrivers/Support/SUPDrvInternal.h | 4 +
src/VBox/HostDrivers/Support/SUPLib.cpp | 2 +-
src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp | 2 +-
.../HostDrivers/Support/darwin/SUPDrv-darwin.cpp | 105 +-
.../HostDrivers/Support/freebsd/SUPDrv-freebsd.c | 3 -
src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c | 93 +-
src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp | 3 -
.../HostDrivers/Support/solaris/SUPDrv-solaris.c | 3 -
src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp | 181 +-
.../Support/win/SUPHardenedVerifyImage-win.cpp | 26 +-
.../Support/win/SUPR3HardenedMain-win.cpp | 26 +-
.../Support/win/SUPR3HardenedMainA-win.asm | 12 +
.../Support/win/SUPR3HardenedMainImports-win.cpp | 70 +-
.../VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp | 11 +-
.../VBoxNetAdp/linux/VBoxNetAdp-linux.c | 7 +-
.../VBoxNetAdp/solaris/VBoxNetAdp-solaris.c | 6 +-
.../VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp | 13 +-
.../VBoxNetFlt/linux/VBoxNetFlt-linux.c | 69 +-
src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c | 2 +
src/VBox/HostServices/GuestProperties/service.cpp | 163 ++
.../SharedOpenGL/crserverlib/server_dispatch.py | 0
.../crserverlib/server_dispatch_header.py | 0
.../SharedOpenGL/crserverlib/server_get.py | 0
.../SharedOpenGL/crserverlib/server_retval.py | 0
.../HostServices/SharedOpenGL/unpacker/unpack.py | 0
.../SharedOpenGL/unpacker/unpack_extend.py | 0
.../SharedOpenGL/unpacker/unpack_header.py | 0
src/VBox/Installer/linux/rpm/rules | 2 +-
src/VBox/Installer/linux/vboxdrv.sh.in | 4 +-
src/VBox/Main/glue/constants-python.xsl | 0
src/VBox/Main/idl/VirtualBox.xidl | 7 +-
src/VBox/Main/include/ConsoleImpl.h | 4 +
src/VBox/Main/include/MachineImpl.h | 5 +-
src/VBox/Main/src-client/ConsoleImpl.cpp | 43 +-
src/VBox/Main/src-client/DisplayImpl.cpp | 6 +-
src/VBox/Main/src-server/ApplianceImplExport.cpp | 3 +-
src/VBox/Main/src-server/MachineImpl.cpp | 53 +-
src/VBox/Runtime/Makefile.kmk | 50 +-
src/VBox/Runtime/common/checksum/alt-sha1.cpp | 28 +-
src/VBox/Runtime/common/checksum/alt-sha256.cpp | 30 +
src/VBox/Runtime/common/checksum/alt-sha512.cpp | 60 +
src/VBox/Runtime/common/checksum/openssl-sha1.cpp | 18 +-
.../Runtime/common/checksum/openssl-sha256.cpp | 30 +
.../Runtime/common/checksum/openssl-sha512.cpp | 30 +
.../common/crypto/RTCrStoreCertAddFromFile.cpp | 114 -
.../crypto/RTCrStoreCertAddFromJavaKeyStore.cpp | 310 +++
...RTCrStoreCertAddWantedFromFishingExpedition.cpp | 247 ++
.../common/crypto/RTCrStoreCertExportAsPem.cpp | 137 +
src/VBox/Runtime/common/crypto/pemfile.cpp | 248 +-
.../Runtime/common/crypto/store-cert-add-basic.cpp | 849 ++++++
src/VBox/Runtime/common/crypto/store-inmem.cpp | 31 +-
src/VBox/Runtime/common/crypto/store-internal.h | 3 +
src/VBox/Runtime/common/crypto/store.cpp | 28 +-
src/VBox/Runtime/common/crypto/tsp-template.h | 6 +-
src/VBox/Runtime/common/crypto/x509-core.cpp | 3 +-
src/VBox/Runtime/common/ldr/ldrPE.cpp | 19 +-
src/VBox/Runtime/common/misc/http.cpp | 601 -----
src/VBox/Runtime/common/misc/uri.cpp | 945 ++++---
.../path/RTPathEnsureTrailingSeparator.cpp} | 66 +-
src/VBox/Runtime/common/path/RTPathGlob.cpp | 2140 +++++++++++++++
src/VBox/Runtime/common/string/memrchr.asm | 90 +
src/VBox/Runtime/common/vfs/vfsstdfile.cpp | 3 +
.../RTCrStoreCreateSnapshotById-generic.cpp | 148 ++
src/VBox/Runtime/generic/RTMpOnPair-generic.cpp | 137 +
src/VBox/Runtime/generic/createtemp-generic.cpp | 46 +
src/VBox/Runtime/generic/fs-stubs-generic.cpp | 14 +
src/VBox/Runtime/generic/http-curl.cpp | 2449 ++++++++++++++++++
.../darwin/RTLogWriteDebugger-r0drv-darwin.cpp | 3 +-
.../r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp | 3 +-
.../Runtime/r0drv/darwin/alloc-r0drv-darwin.cpp | 22 +-
.../Runtime/r0drv/darwin/assert-r0drv-darwin.cpp | 4 +
.../r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp | 12 +
.../Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp | 7 +
.../Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp | 56 +-
.../r0drv/darwin/memuserkernel-r0drv-darwin.cpp | 4 +
src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp | 23 +
.../Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp | 13 +
.../r0drv/darwin/semeventmulti-r0drv-darwin.cpp | 16 +
.../r0drv/darwin/semfastmutex-r0drv-darwin.cpp | 11 +
.../Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp | 26 +-
.../Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp | 51 +-
src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h | 17 +-
.../Runtime/r0drv/darwin/thread-r0drv-darwin.cpp | 8 +
.../Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp | 3 +
.../r0drv/darwin/threadpreempt-r0drv-darwin.cpp | 10 +
.../Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp | 29 +-
.../r0drv/linux/RTLogWriteDebugger-r0drv-linux.c | 2 +
src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c | 20 +-
src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c | 4 +
.../Runtime/r0drv/linux/initterm-r0drv-linux.c | 20 +-
src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c | 96 +-
.../r0drv/linux/memuserkernel-r0drv-linux.c | 17 +-
src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c | 9 +
.../r0drv/linux/mpnotification-r0drv-linux.c | 4 +
.../Runtime/r0drv/linux/semevent-r0drv-linux.c | 11 +
.../r0drv/linux/semeventmulti-r0drv-linux.c | 11 +
.../Runtime/r0drv/linux/semfastmutex-r0drv-linux.c | 11 +
.../Runtime/r0drv/linux/semmutex-r0drv-linux.c | 51 +-
.../Runtime/r0drv/linux/spinlock-r0drv-linux.c | 6 +
src/VBox/Runtime/r0drv/linux/the-linux-kernel.h | 6 +-
src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c | 8 +-
src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c | 14 +-
.../r0drv/linux/threadctxhooks-r0drv-linux.c | 28 +
src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c | 3 +
src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c | 37 +-
src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp | 3 +-
src/VBox/Runtime/r0drv/nt/symdbdata.h | 44 +
.../darwin/RTCrStoreCreateSnapshotById-darwin.cpp | 249 ++
src/VBox/Runtime/r3/nt/fs-nt.cpp | 5 +
src/VBox/Runtime/r3/posix/fs-posix.cpp | 14 +
.../r3/win/RTCrStoreCreateSnapshotById-win.cpp | 169 ++
src/VBox/Runtime/r3/win/fileio-win.cpp | 49 +-
src/VBox/Runtime/r3/win/fs-win.cpp | 6 +
src/VBox/Runtime/r3/xml.cpp | 18 +-
src/VBox/Runtime/testcase/Makefile.kmk | 4 +
src/VBox/Runtime/testcase/tstRTBitOperations.cpp | 13 +-
src/VBox/Runtime/testcase/tstRTHttp.cpp | 17 +-
src/VBox/Runtime/testcase/tstRTPathGlob.cpp | 82 +
src/VBox/Runtime/testcase/tstRTUri.cpp | 555 ++--
src/VBox/Runtime/tools/Makefile.kmk | 7 +
src/VBox/Runtime/tools/RTHttp.cpp | 157 ++
src/VBox/Runtime/tools/RTSignTool.cpp | 7 +-
src/VBox/VMM/VMMR0/VMMR0.cpp | 276 +-
src/VBox/VMM/VMMR3/PDMDriver.cpp | 7 +-
src/libs/Makefile.kmk | 16 +-
src/libs/xpcom18a4/python/__init__.py | 0
src/libs/xpcom18a4/python/components.py | 0
src/libs/xpcom18a4/python/nsError.py | 0
src/libs/xpcom18a4/python/tools/tracer_demo.py | 0
279 files changed, 19629 insertions(+), 8182 deletions(-)
diff --git a/Config.kmk b/Config.kmk
index 36cd726..f41c2c0 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -208,7 +208,7 @@ VBOX_VERSION_MINOR = 3
# This is the current build number. It should be increased every time we publish a
# new build. The define is available in every source file. Only even build numbers
# will be published, odd numbers are set during development.
-VBOX_VERSION_BUILD = 30
+VBOX_VERSION_BUILD = 32
# The raw version string. This *must not* contain any other information/fields than
# major, minor and build revision (as it is now) -- also will be used for host/guest version
# comparison.
@@ -2859,19 +2859,19 @@ VBOXLNX32GUEST_SUFF_LIB = .a
# SDKs for external libraries.
#
SDK_VBOX_LIBXML2 = .
-SDK_VBOX_LIBXML2_INCS ?= $(PATH_ROOT)/src/libs/libxml2-2.6.31/include
+SDK_VBOX_LIBXML2_INCS ?= $(PATH_ROOT)/src/libs/libxml2-2.9.2/include
SDK_VBOX_LIBXML2_DEFS ?= _REENTRANT
SDK_VBOX_LIBXML2_DEFS.win += WIN32 _WINDOWS _MBCS
# note: no linking to LIB here, we do that explicitly in src/VBox/Runtime/Makefile.kmk to link
# libxml against VBoxRT
SDK_VBOX_LIBPNG = .
-SDK_VBOX_LIBPNG_INCS ?= $(PATH_ROOT)/src/libs/libpng-1.2.8
+SDK_VBOX_LIBPNG_INCS ?= $(PATH_ROOT)/src/libs/libpng-1.2.53
SDK_VBOX_LIBPNG_LIBS ?= $(PATH_STAGE_LIB)/VBox-libpng$(VBOX_SUFF_LIB)
SDK_VBOX_ZLIB = .
if1of ($(KBUILD_TARGET), os2 solaris win)
- SDK_VBOX_ZLIB_INCS ?= $(PATH_ROOT)/src/libs/zlib-1.2.6
+ SDK_VBOX_ZLIB_INCS ?= $(PATH_ROOT)/src/libs/zlib-1.2.8
SDK_VBOX_ZLIB_LIBS ?= $(PATH_STAGE_LIB)/VBox-zlib$(VBOX_SUFF_LIB)
else
SDK_VBOX_ZLIB_INCS ?=
@@ -2923,12 +2923,12 @@ SDK_VBoxOpenSslExtPack_LIBS = \
ifdef VBOX_WITH_S3
VBOX_WITH_LIBCURL = 1
SDK_VBOX_LIBCURL = .
-SDK_VBOX_LIBCURL_INCS ?= $(PATH_ROOT)/src/libs/curl-7.42.1/include
+SDK_VBOX_LIBCURL_INCS ?= $(PATH_ROOT)/src/libs/curl-7.45.0/include
SDK_VBOX_LIBCURL_LIBS ?= $(PATH_STAGE_LIB)/VBox-libcurl$(VBOX_SUFF_LIB)
SDK_VBOX_LIBCURL_DEFS ?= BUILDING_LIBCURL
SDK_VBOX_LIBCURL-x86 = .
-SDK_VBOX_LIBCURL-x86_INCS ?= $(PATH_ROOT)/src/libs/curl-7.42.1/include
+SDK_VBOX_LIBCURL-x86_INCS ?= $(PATH_ROOT)/src/libs/curl-7.45.0/include
SDK_VBOX_LIBCURL-x86_LIBS.x86 ?= $(PATH_STAGE_LIB)/VBox-libcurl-x86$(VBOX_SUFF_LIB)
SDK_VBOX_LIBCURL-x86_DEFS ?= BUILDING_LIBCURL
endif
@@ -5734,7 +5734,7 @@ endif
SVN ?= svn$(HOSTSUFF_EXE)
VBOX_SVN_REV_KMK = $(PATH_OUT)/revision.kmk
ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 101610 $ )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 103443 $ )
VBOX_SVN_DEP := $(firstword $(wildcard $(PATH_ROOT)/.svn/wc.db $(abspath $(PATH_ROOT)/../.svn/wc.db) $(abspath $(PATH_ROOT)/../../.svn/wc.db) $(PATH_ROOT)/.svn/entries))
ifeq ($(which $(SVN)),)
VBOX_SVN_DEP :=
diff --git a/doc/manual/en_US/user_BasicConcepts.xml b/doc/manual/en_US/user_BasicConcepts.xml
index fb050c1..197916c 100644
--- a/doc/manual/en_US/user_BasicConcepts.xml
+++ b/doc/manual/en_US/user_BasicConcepts.xml
@@ -45,7 +45,8 @@
<glossdef>
<para>All versions, editions and service packs are fully supported
(including 64-bit versions, under the preconditions listed below).
- Guest Additions are available.</para>
+ Guest Additions are available. Windows 8 and later requires hardware
+ virtualization to be enabled.</para>
</glossdef>
</glossentry>
diff --git a/doc/manual/en_US/user_GuestAdditions.xml b/doc/manual/en_US/user_GuestAdditions.xml
index 73fc1c1..7d0a50b 100644
--- a/doc/manual/en_US/user_GuestAdditions.xml
+++ b/doc/manual/en_US/user_GuestAdditions.xml
@@ -1079,6 +1079,14 @@
<para>Currently only Linux and Solaris Guest Additions support
symlinks.</para>
</listitem>
+
+ <listitem>
+ <para>For security reasons the guest OS is not allowed to create
+ symlinks by default. If you trust the guest OS to not abuse the
+ functionality, you can enable creation of symlinks for "sharename"
+ with:
+ <screen>VBoxManage setextradata "VM name" VBoxInternal2/SharedFoldersEnableSymlinksCreate/sharename 1</screen></para>
+ </listitem>
</orderedlist></para>
<sect2 id="sf_mount_manual">
@@ -1729,7 +1737,11 @@ Name: /VirtualBox/GuestInfo/OS/Version, value: #59-Ubuntu SMP Thu Jan 28 01:23:0
of fused pages, whereas the per-VM metric
<computeroutput>Guest/RAM/Usage/Shared</computeroutput> will return the
amount of fused memory for a given VM. Please refer to <xref
- linkend="metrics" /> for information on how to query metrics.</para>
+ linkend="metrics" /> for information on how to query metrics.</para>
+
+ <note><para>Enabling Page Fusion might indirectly increase the chances
+ for malicious guests to successfully attack other VMs running on the
+ same host, see <xref linkend="pot-insecure"/>.</para></note>
</sect2>
</sect1>
</chapter>
diff --git a/doc/manual/en_US/user_Security.xml b/doc/manual/en_US/user_Security.xml
index 61f0c60..c530745 100644
--- a/doc/manual/en_US/user_Security.xml
+++ b/doc/manual/en_US/user_Security.xml
@@ -311,7 +311,7 @@
</sect2>
-->
- <sect2>
+ <sect2 id="pot-insecure">
<title>Potentially insecure operations</title>
<para>The following features of VirtualBox can present security
@@ -334,6 +334,17 @@
</listitem>
<listitem>
+ <para>When Page Fusion (see <xref linkend="guestadd-pagefusion"/>)
+ is enabled, it is possible that a side-channel opens up that allows
+ a malicious guest to determin the address space layout (i.e. where
+ DLLs are typically loaded) of one other VM running on the same host.
+ This information leak in it self is harmless, however the malicious
+ guest may use it to optimize attack against that VM via unrelated
+ attack vectors. It is recommended to only enable Page Fusion if you
+ do not think this is a concern in your setup.</para>
+ </listitem>
+
+ <listitem>
<para>When using the VirtualBox web service to control a VirtualBox
host remotely, connections to the web service (through which the API
calls are transferred via SOAP XML) are not encrypted, but use plain
diff --git a/doc/manual/en_US/user_Storage.xml b/doc/manual/en_US/user_Storage.xml
index ee9cd6c..10eb7a9 100644
--- a/doc/manual/en_US/user_Storage.xml
+++ b/doc/manual/en_US/user_Storage.xml
@@ -483,12 +483,12 @@
<note>
<para>As a special exception, immutable images are
<emphasis>not</emphasis> reset if they are attached to a machine
- whose last snapshot was taken while the machine was running (a
- so-called "online" snapshot). As a result, if the machine's current
- snapshot is such an "online" snapshot, its immutable images behave
- exactly like the "normal" images described previously. To re-enable
- the automatic resetting of such images, delete the current snapshot
- of the machine.</para>
+ in saved state or whose last snapshot was taken while the machine
+ was running (a so-called "online" snapshot). As a result, if the
+ machine's current snapshot is such an "online" snapshot, its
+ immutable images behave exactly like the "normal" images described
+ previously. To re-enable the automatic resetting of such images,
+ delete the current snapshot of the machine.</para>
</note>
<para>Again, technically, VirtualBox never writes to an immutable
diff --git a/doc/manual/en_US/user_Troubleshooting.xml b/doc/manual/en_US/user_Troubleshooting.xml
index 65280c6..b9fcc8d 100644
--- a/doc/manual/en_US/user_Troubleshooting.xml
+++ b/doc/manual/en_US/user_Troubleshooting.xml
@@ -952,6 +952,26 @@
</orderedlist>
</sect2>
+ <sect2>
+ <title>Windows 3.x limited to 64 MB RAM</title>
+
+ <para>Windows 3.x guests are typically limited to 64 MB RAM, even if a VM is assigned
+ much more memory. While Windows 3.1 is theoretically capable of using up to 512 MB RAM,
+ it only uses memory available through the XMS interface. Versions of HIMEM.SYS (the
+ Microsoft XMS manager) shipped with MS-DOS and Microsoft Windows 3.x can only use
+ up to 64 MB on standard PCs.</para>
+
+ <para>This is a HIMEM.SYS limitation documented by Microsoft in Knowledge base
+ article KB 116256.
+ Windows 3.1 memory limits are described in detail in Microsoft Knowledge base
+ article KB 84388.</para>
+
+ <para>It is possible for Windows 3.x guests to utilize more than 64 MB RAM if a
+ different XMS provider is used. That could be a newer HIMEM.SYS version (such as
+ that shipped with Windows 98), or a more capable third-party memory manager
+ (such as QEMM).</para>
+ </sect2>
+
</sect1>
<sect1 id="ts_lin-x11-guests">
diff --git a/doc/manual/en_US/user_VBoxManage.xml b/doc/manual/en_US/user_VBoxManage.xml
index 9c579da..a8ff58f 100644
--- a/doc/manual/en_US/user_VBoxManage.xml
+++ b/doc/manual/en_US/user_VBoxManage.xml
@@ -1383,11 +1383,11 @@ Virtual system 0:
<computeroutput>--legacy09</computeroutput> option.</para>
<para>To specify options controlling the exact content of the appliance
- file, you can use <computeroutput>--option</computeroutput> to request the
+ file, you can use <computeroutput>--options</computeroutput> to request the
creation of a manifest file (encouraged, allows detection of corrupted
appliances on import), the additional export of DVD images, and the
exclusion of MAC addresses. You can specify a list of options, e.g.
- <computeroutput>--option manifest,nomacs</computeroutput>. For details,
+ <computeroutput>--options manifest,nomacs</computeroutput>. For details,
check the help output of <computeroutput>VBoxManage export</computeroutput>.</para>
</sect1>
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index ebdddf5..eb4b325 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -1,6 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<sect1>
+ <title>Version 4.3.32 (2015-10-20)</title>
+
+ <para>This is a maintenance release. The following items were fixed and/or
+ added:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>Bridged Networking: fix handling of guest DHCP requests
+ without UDP checksum when bridging to a wireless interface
+ (bug #14615).</para>
+ </listitem>
+
+ <listitem>
+ <para>VRDP: allow Windows 10 RDP clients (bug #14216)</para>
+ </listitem>
+
+ <listitem>
+ <para>Mac OS X hosts: another fix for hosts with activated SMAP (Broadwell
+ and later; bug #13951)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows hosts: hardening fixes</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: check then name space before attaching to a host
+ network interface (bug #13795)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: fixed <emphasis>VM_INVALID_STATE</emphasis> Guru Meditation
+ on Linux 4.2 kernels (bug #14531)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: more SMAP fixes</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: Linux 4.2 fix</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: Linux 4.3 compile fixes</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: installer fix for certain systems (bug #14627)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: Linux 4.2 fixes (bug #14227)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: improved the performance of
+ <emphasis>stat()</emphasis> to speed up certain file operations
+ on shared folders</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: be more forgiving if the compilation of the
+ vboxvideo module fails</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows Additions: fixed a potential crash in the WDDM driver
+ with Windows 10 (bug #14190)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows Additions: fixed video playback with VLC and Windows Media Player
+ when the WDDM driver is used and 3D is not enabled</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows Additions: fixed problems with 3D acceleration on Windows hosts with
+ Intel HD graphics (bug #14670)</para>
+ </listitem>
+
+ <listitem>
+ <para>X11 Additions: fixed a crash on log-out with the KDM display
+ manager (bug #14341)</para>
+ </listitem>
+
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1>
<title>Version 4.3.30 (2015-07-10)</title>
<para>This is a maintenance release. The following items were fixed and/or
diff --git a/include/VBox/err.h b/include/VBox/err.h
index d8429c3..089d48a 100644
--- a/include/VBox/err.h
+++ b/include/VBox/err.h
@@ -1776,6 +1776,10 @@
#define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741)
/** Type error opening the ApiPort LPC object. */
#define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742)
+/** The process trying to open VBoxDrv is not a budding VM process (1). */
+#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1 (-3748)
+/** The process trying to open VBoxDrv is not a budding VM process (2). */
+#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2 (-3748)
/** @} */
diff --git a/include/VBox/sup.h b/include/VBox/sup.h
index 4dbda19..bc8517d 100644
--- a/include/VBox/sup.h
+++ b/include/VBox/sup.h
@@ -97,6 +97,8 @@ typedef enum SUPPAGINGMODE
*/
/** GDT is read-only. */
#define SUPKERNELFEATURES_GDT_READ_ONLY RT_BIT(0)
+/** SMAP is possibly enabled. */
+#define SUPKERNELFEATURES_SMAP RT_BIT(1)
/** @} */
@@ -1429,14 +1431,34 @@ SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3);
SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip);
SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps);
SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession);
-SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...);
SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void);
-SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void);
SUPR0DECL(RTCCUINTREG) SUPR0ChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask);
SUPR0DECL(int) SUPR0EnableVTx(bool fEnable);
SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void);
SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended);
+SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr);
+
+/**
+ * Writes to the debugger and/or kernel log.
+ *
+ * The length of the formatted message is somewhat limited, so keep things short
+ * and to the point.
+ *
+ * @returns Number of bytes written, mabye.
+ * @param pszFormat IPRT format string.
+ * @param ... Arguments referenced by the format string.
+ */
+SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...);
+
+/**
+ * Returns configuration flags of the host kernel.
+ *
+ * @returns Combination of SUPKERNELFEATURES_XXX flags.
+ */
+SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void);
+
+
/** @name Absolute symbols
* Take the address of these, don't try call them.
* @{ */
diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h
index bd54da8..28b7b36 100644
--- a/include/VBox/vmm/pdmifs.h
+++ b/include/VBox/vmm/pdmifs.h
@@ -616,20 +616,21 @@ typedef struct PDMIDISPLAYPORT
const uint8_t *pbSrc, int32_t xSrc, int32_t ySrc, uint32_t cxSrc, uint32_t cySrc, uint32_t cbSrcLine, uint32_t cSrcBitsPerPixel,
uint8_t *pbDst, int32_t xDst, int32_t yDst, uint32_t cxDst, uint32_t cyDst, uint32_t cbDstLine, uint32_t cDstBitsPerPixel));
-#ifdef VBOX_WITH_VMSVGA
/**
- * Inform the VGA device of viewport changes (as a result of e.g. scrolling)
+ * Inform the VGA device of viewport changes (as a result of e.g. scrolling).
*
* @param pInterface Pointer to this interface.
- * @param uScreenId The screen updates are for.
+ * @param idScreen The screen updates are for.
* @param x The upper left corner x coordinate of the new viewport rectangle
* @param y The upper left corner y coordinate of the new viewport rectangle
* @param cx The width of the new viewport rectangle
* @param cy The height of the new viewport rectangle
- * @thread The emulation thread.
+ * @thread GUI thread?
+ *
+ * @remarks Is allowed to be NULL.
*/
- DECLR3CALLBACKMEMBER(void, pfnSetViewPort,(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy));
-#endif
+ DECLR3CALLBACKMEMBER(void, pfnSetViewport,(PPDMIDISPLAYPORT pInterface,
+ uint32_t idScreen, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy));
/**
* Send a video mode hint to the VGA device.
diff --git a/include/iprt/asm-amd64-x86.h b/include/iprt/asm-amd64-x86.h
index fa77cb2..5c70fb4 100644
--- a/include/iprt/asm-amd64-x86.h
+++ b/include/iprt/asm-amd64-x86.h
@@ -495,6 +495,184 @@ DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags)
/**
+ * Modifies the [RE]FLAGS register.
+ * @returns Original value.
+ * @param fAndEfl Flags to keep (applied first).
+ * @param fOrEfl Flags to be set.
+ */
+#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 15
+DECLASM(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMChangeFlags(RTCCUINTREG fAndEfl, RTCCUINTREG fOrEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "andq %0, %1\n\t"
+ "orq %3, %1\n\t"
+ "mov %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl),
+ "=r" (fAndEfl)
+ : "1" (fAndEfl),
+ "rn" (fOrEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "andl %1, (%%esp)\n\t"
+ "orl %2, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl),
+ "rn" (fOrEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags((fOldEfl & fAndEfl) | fOrEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rdx, [fAndEfl]
+ mov rcx, [fOrEfl]
+ pushfq
+ mov rax, [rsp]
+ and rdx, rax
+ or rdx, rcx
+ mov [rsp], rdx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov edx, [fAndEfl]
+ mov ecx, [fOrEfl]
+ pushfd
+ mov eax, [esp]
+ and edx, eax
+ or edx, ecx
+ mov [esp], edx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
+ * Modifies the [RE]FLAGS register by ORing in one or more flags.
+ * @returns Original value.
+ * @param fOrEfl The flags to be set (ORed in).
+ */
+#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 15
+DECLASM(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMAddFlags(RTCCUINTREG fOrEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "orq %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fOrEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "orl %1, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fOrEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags(fOldEfl | fOrEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rcx, [fOrEfl]
+ pushfq
+ mov rdx, [rsp]
+ or [rsp], rcx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov ecx, [fOrEfl]
+ pushfd
+ mov edx, [esp]
+ or [esp], ecx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
+ * Modifies the [RE]FLAGS register by AND'ing out one or more flags.
+ * @returns Original value.
+ * @param fAndEfl The flags to keep.
+ */
+#if RT_INLINE_ASM_EXTERNAL && RT_INLINE_ASM_USES_INTRIN < 15
+DECLASM(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl);
+#else
+DECLINLINE(RTCCUINTREG) ASMClearFlags(RTCCUINTREG fAndEfl)
+{
+ RTCCUINTREG fOldEfl;
+# if RT_INLINE_ASM_GNU_STYLE
+# ifdef RT_ARCH_AMD64
+ __asm__ __volatile__("pushfq\n\t"
+ "movq (%%rsp), %0\n\t"
+ "andq %1, (%%rsp)\n\t"
+ "popfq\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl) );
+# else
+ __asm__ __volatile__("pushfl\n\t"
+ "movl (%%esp), %0\n\t"
+ "andl %1, (%%esp)\n\t"
+ "popfl\n\t"
+ : "=&r" (fOldEfl)
+ : "rn" (fAndEfl) );
+# endif
+# elif RT_INLINE_ASM_USES_INTRIN >= 15
+ fOldEfl = __readeflags();
+ __writeeflags(fOldEfl & fAndEfl);
+# else
+ __asm
+ {
+# ifdef RT_ARCH_AMD64
+ mov rdx, [fAndEfl]
+ pushfq
+ mov rdx, [rsp]
+ and [rsp], rdx
+ popfq
+ mov [fOldEfl], rax
+# else
+ mov edx, [fAndEfl]
+ pushfd
+ mov edx, [esp]
+ and [esp], edx
+ popfd
+ mov [fOldEfl], eax
+# endif
+ }
+# endif
+ return fOldEfl;
+}
+#endif
+
+
+/**
* Gets the content of the CPU timestamp counter register.
*
* @returns TSC.
diff --git a/include/iprt/asm.h b/include/iprt/asm.h
index 11c61af..3ff9de0 100644
--- a/include/iprt/asm.h
+++ b/include/iprt/asm.h
@@ -4276,7 +4276,7 @@ DECLINLINE(void) ASMBitSetRange(volatile void *pvBitmap, int32_t iBitStart, int3
int iStart = iBitStart & ~31;
int iEnd = iBitEnd & ~31;
if (iStart == iEnd)
- *pu32 |= ((1 << (iBitEnd - iBitStart)) - 1) << iBitStart;
+ *pu32 |= ((1 << (iBitEnd - iBitStart)) - 1) << (iBitStart & 31);
else
{
/* bits in first dword. */
diff --git a/include/iprt/asn1.h b/include/iprt/asn1.h
index 987e3a2..2e86628 100644
--- a/include/iprt/asn1.h
+++ b/include/iprt/asn1.h
@@ -604,6 +604,7 @@ RTDECL(int) RTAsn1Dummy_InitEx(PRTASN1DUMMY pThis);
*/
DECLINLINE(int) RTAsn1Dummy_Init(PRTASN1DUMMY pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
{
+ NOREF(pAllocator);
return RTAsn1Dummy_InitEx(pThis);
}
@@ -1213,7 +1214,10 @@ RTDECL(int) RTAsn1ContextTagN_Clone(PRTASN1CONTEXTTAG pThis, PCRTASN1CONTEXTTAG
typedef RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) *RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag); \
DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Init)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \
PCRTASN1ALLOCATORVTABLE pAllocator) \
- { return RTAsn1ContextTagN_Init((PRTASN1CONTEXTTAG)pThis, a_uTag); } \
+ { \
+ NOREF(pAllocator); \
+ return RTAsn1ContextTagN_Init((PRTASN1CONTEXTTAG)pThis, a_uTag); \
+ } \
DECLINLINE(int) RT_CONCAT3(RTAsn1ContextTag,a_uTag,_Clone)(RT_CONCAT(PRTASN1CONTEXTTAG,a_uTag) pThis, \
RT_CONCAT(RTASN1CONTEXTTAG,a_uTag) const *pSrc) \
{ return RTAsn1ContextTagN_Clone((PRTASN1CONTEXTTAG)pThis, (PCRTASN1CONTEXTTAG)pSrc, a_uTag); } \
diff --git a/include/iprt/cdefs.h b/include/iprt/cdefs.h
index df36723..27f87af 100644
--- a/include/iprt/cdefs.h
+++ b/include/iprt/cdefs.h
@@ -1411,6 +1411,7 @@
* String constant tuple - string constant, strlen(string constant).
*
* @param a_szConst String constant.
+ * @sa RTSTRTUPLE
*/
#define RT_STR_TUPLE(a_szConst) a_szConst, (sizeof(a_szConst) - 1)
diff --git a/include/iprt/crypto/digest.h b/include/iprt/crypto/digest.h
index 374196b..9b70f57 100644
--- a/include/iprt/crypto/digest.h
+++ b/include/iprt/crypto/digest.h
@@ -145,7 +145,7 @@ typedef RTCRDIGESTDESC const *PCRTCRDIGESTDESC;
* RTCrDigestCreate. This is optional, fewer
* algortihms are available if not specified.
*/
-RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void *ppvOpaque);
+RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void **ppvOpaque);
/**
* Finds a cryptographic hash / message digest descriptor by object identifier
@@ -159,7 +159,7 @@ RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void
* RTCrDigestCreate. This is optional, fewer
* algortihms are available if not specified.
*/
-RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjId(PCRTASN1OBJID pObjId, void *ppvOpaque);
+RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque);
RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByType(RTDIGESTTYPE enmDigestType);
RTDECL(int) RTCrDigestCreateByObjIdString(PRTCRDIGEST phDigest, const char *pszObjId);
diff --git a/include/iprt/crypto/pem.h b/include/iprt/crypto/pem.h
index 616ffad..5a0d724 100644
--- a/include/iprt/crypto/pem.h
+++ b/include/iprt/crypto/pem.h
@@ -101,13 +101,34 @@ typedef RTCRPEMSECTION const *PCRTCRPEMSECTION;
/**
- * Frees sections returned by RTCrPemReadFile.
+ * Frees sections returned by RTCrPemReadFile and RTCrPemParseContent.
* @returns IPRT status code.
* @param pSectionHead The first section.
*/
RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead);
/**
+ * Parses the given data and returns a list of binary sections.
+ *
+ * If the file isn't an ASCII file or if no markers were found, the entire file
+ * content is returned as one single section (with pMarker = NULL).
+ *
+ * @returns IPRT status code.
+ * @retval VINF_EOF if the file is empty. The ppSectionHead value will be NULL.
+ *
+ * @param pvContent The content bytes to parse.
+ * @param cbContent The number of content bytes.
+ * @param fFlags RTCRPEMREADFILE_F_XXX.
+ * @param paMarkers Array of one or more section markers to look for.
+ * @param cMarkers Number of markers in the array.
+ * @param ppSectionHead Where to return the head of the section list. Call
+ * RTCrPemFreeSections to free.
+ * @param pErrInfo Where to return extend error info. Optional.
+ */
+RTDECL(int) RTCrPemParseContent(void const *pvContent, size_t cbContent, uint32_t fFlags,
+ PCRTCRPEMMARKER paMarkers, size_t cMarkers, PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo);
+
+/**
* Reads the content of the given file and returns a list of binary sections
* found in the file.
*
@@ -115,15 +136,24 @@ RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead);
* content is returned as one single section (with pMarker = NULL).
*
* @returns IPRT status code.
+ * @retval VINF_EOF if the file is empty. The ppSectionHead value will be NULL.
+ *
* @param pszFilename The path to the file to read.
- * @param fFlags Flags reserved for future hacks.
+ * @param fFlags RTCRPEMREADFILE_F_XXX.
* @param paMarkers Array of one or more section markers to look for.
* @param cMarkers Number of markers in the array.
- * @param ppSectionHead Where to return the head of the section list.
+ * @param ppSectionHead Where to return the head of the section list. Call
+ * RTCrPemFreeSections to free.
* @param pErrInfo Where to return extend error info. Optional.
*/
RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo);
+/** @name RTCRPEMREADFILE_F_XXX - Flags for RTCrPemReadFile and
+ * RTCrPemParseContent.
+ * @{ */
+/** Continue on encoding error. */
+#define RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR RT_BIT(0)
+/** @} */
/** @} */
diff --git a/include/iprt/crypto/store.h b/include/iprt/crypto/store.h
index 7c10a16..6b05e0a 100644
--- a/include/iprt/crypto/store.h
+++ b/include/iprt/crypto/store.h
@@ -28,6 +28,7 @@
#include <iprt/crypto/x509.h>
#include <iprt/crypto/taf.h>
+#include <iprt/sha.h>
RT_C_DECLS_BEGIN
@@ -57,14 +58,246 @@ typedef struct RTCRSTORECERTSEARCH
typedef RTCRSTORECERTSEARCH *PRTCRSTORECERTSEARCH;
+/**
+ * Info about a wanted certificate.
+ *
+ * All the search criteria are optional, but for a safe and efficient search
+ * it's recommended to specify all possible ones. If none are given, the search
+ * function will fail.
+ *
+ * For use with RTCrStoreCertAddFromFishingExpedition and others.
+ */
+typedef struct RTCRCERTWANTED
+{
+ /** The certificate subject name, optional.
+ * The format is: "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" */
+ const char *pszSubject;
+ /** The size of the DER (ASN.1) encoded certificate, optional (0). */
+ uint16_t cbEncoded;
+ /** Set if abSha1 contains a valid SHA-1 fingerprint. */
+ bool fSha1Fingerprint;
+ /** Set if abSha512 contains a valid SHA-512 fingerprint. */
+ bool fSha512Fingerprint;
+ /** The SHA-1 fingerprint (of the encoded data). */
+ uint8_t abSha1[RTSHA1_HASH_SIZE];
+ /** The SHA-512 fingerprint (of the encoded data). */
+ uint8_t abSha512[RTSHA512_HASH_SIZE];
+ /** User pointer for directly associating other data with the entry.
+ * Subclassing the structure isn't possible because it's passed as an array. */
+ void const *pvUser;
+} RTCRCERTWANTED;
+/** Pointer to a const certificat wanted structure. */
+typedef RTCRCERTWANTED const *PCRTCRCERTWANTED;
+
+
+/**
+ * Standard store identifiers.
+ *
+ * This is a least common denominator approach to system specific certificate
+ * stores, could be extended to include things other than certificates later if
+ * we need it.
+ *
+ * Windows has lots of different stores, they'll be combined by the
+ * implementation, possibly leading to duplicates. The user stores on Windows
+ * seems to be unioned with the system (machine) stores.
+ *
+ * Linux may have different stores depending on the distro/version/installation,
+ * in which case we'll combine them, which will most likely lead to
+ * duplicates just like on windows. Haven't found any easily accessible
+ * per-user certificate stores on linux yet, so they'll all be empty.
+ *
+ * Mac OS X seems a lot simpler, at least from the GUI point of view. Each
+ * keychains as a "Certificates" folder (the "My Certificates" folder seems to
+ * only be a matching of "Keys" and "Certificates"). However, there are two
+ * system keychains that we need to combine, "System" and "System Roots". As
+ * with Windows and Linux, there is a possibility for duplicates here.
+ *
+ * On solaris we have currently no idea where to look for a certificate store,
+ * so that doesn't yet work.
+ *
+ * Because of the OS X setup, we do not provide any purpose specific
+ */
+typedef enum RTCRSTOREID
+{
+ /** Mandatory invalid zero value. */
+ RTCRSTOREID_INVALID = 0,
+ /** Open the certificate store of the current user containing trusted
+ * CAs and certificates.
+ * @remarks This may or may not include all the certificates in the system
+ * store, that's host dependent. So, you better look in both. */
+ RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES,
+ /** Open the certificate store of the system containg trusted CAs
+ * and certificates. */
+ RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES,
+ /** End of valid values. */
+ RTCRSTOREID_END,
+ /** Traditional enum type compression prevention hack. */
+ RTCRSTOREID_32BIT_HACK = 0x7fffffff
+} RTCRSTOREID;
+
+/**
+ * Creates a snapshot of a standard store.
+ *
+ * This will return an in-memory store containing all data from the given store.
+ * There will be no duplicates in this one.
+ *
+ * @returns IPRT status code.
+ * @retval VWRN_ALREADY_EXISTS if the certificate is already present and
+ * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified.
+ * @param phStore Where to return the store handle. Use
+ * RTCrStoreRelease to release it.
+ * @param enmStoreId The store to snapshot.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
+RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo);
+
RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint);
RTDECL(uint32_t) RTCrStoreRetain(RTCRSTORE hStore);
RTDECL(uint32_t) RTCrStoreRelease(RTCRSTORE hStore);
RTDECL(PCRTCRCERTCTX) RTCrStoreCertByIssuerAndSerialNo(RTCRSTORE hStore, PCRTCRX509NAME pIssuer, PCRTASN1INTEGER pSerialNo);
+
+/**
+ * Add a certificate to the store.
+ *
+ * @returns IPRT status code.
+ * @retval VWRN_ALREADY_EXISTS if the certificate is already present and
+ * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified.
+ * @retval VERR_WRITE_PROTECT if the store doesn't support adding.
+ * @param hStore The store to add the certificate to.
+ * @param fFlags RTCRCERTCTX_F_XXX. Encoding must be specified.
+ * RTCRCERTCTX_F_ADD_IF_NOT_FOUND is supported.
+ * @param pvSrc The encoded certificate bytes.
+ * @param cbSrc The size of the encoded certificate.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
RTDECL(int) RTCrStoreCertAddEncoded(RTCRSTORE hStore, uint32_t fFlags, void const *pvSrc, size_t cbSrc, PRTERRINFO pErrInfo);
+
+/**
+ * Adds certificates from files in the specified directory.
+ *
+ * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is
+ * used, an error is returned as an error (and not a warning).
+ *
+ * @param hStore The store to add the certificate(s) to.
+ * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or
+ * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR.
+ * @param pszDir The path to the directory.
+ * @param paSuffixes List of suffixes of files to process.
+ * @param cSuffixes Number of suffixes. If this is 0, all files are
+ * processed.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
+RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir,
+ PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo);
+
+RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
+ const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
+
+/**
+ * Adds certificates from the specified file.
+ *
+ * The supported file formats are:
+ * - PEM (base 64 blobs wrapped in -----BEGIN / END----). Support multiple
+ * certificates in one file.
+ * - Binary DER ASN.1 certificate. Only one per file.
+ * - Java key store version 2.
+ *
+ * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is
+ * used, an error is returned as an error (and not a warning).
+ *
+ * @param hStore The store to add the certificate(s) to.
+ * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or
+ * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR.
+ * @param pszFilename The filename.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo);
+RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
+
+/**
+ * Adds certificates from the specified java key store file.
+ *
+ * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is
+ * used, an error is returned as an error (and not a warning).
+ *
+ * @param hStore The store to add the certificate(s) to.
+ * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or
+ * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR.
+ * @param pszFilename The path to the JKS file.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
+RTDECL(int) RTCrStoreCertAddFromJavaKeyStore(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo);
+
+/**
+ * Adds certificates from an in-memory java key store.
+ *
+ * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is
+ * used, an error is returned as an error (and not a warning).
+ *
+ * @param hStore The store to add the certificate(s) to.
+ * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or
+ * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR.
+ * @param pvContent Pointer to the key store bytes.
+ * @param cbContent The size of the key store.
+ * @param pszErrorName The file name or whatever helpful indicator the
+ * caller want in the error messages.
+ * @param pErrInfo Where to return additional error/warning info.
+ * Optional.
+ */
+RTDECL(int) RTCrStoreCertAddFromJavaKeyStoreInMem(RTCRSTORE hStore, uint32_t fFlags, void const *pvContent, size_t cbContent,
+ const char *pszErrorName, PRTERRINFO pErrInfo);
+
+/**
+ * Adds all certificates from @a hStoreSrc into @a hStore.
+ *
+ * @returns IPRT status code. Even when RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR is
+ * used, an error is returned as an error (and not a warning).
+ *
+ * @param hStore The destination store.
+ * @param fFlags RTCRCERTCTX_F_ADD_IF_NOT_FOUND and/or
+ * RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR.
+ * @param hStoreSrc The source store.
+ */
+RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc);
+
+RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
+
+RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags,
+ PCRTCRCERTWANTED paWanted, size_t cWanted,
+ bool *pafFound, PRTERRINFO pErrInfo);
+
+/**
+ * Exports the certificates in the store to a PEM file
+ *
+ * @returns IPRT status code.
+ * @param hStore The store which certificates should be exported.
+ * @param fFlags Reserved for the future, MBZ.
+ * @param pszFilename The name of the destination PEM file. This will
+ * be truncated.
+ */
+RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename);
+
+/**
+ * Counts the number of certificates in the store.
+ *
+ * @returns Certificate count on success, UINT32_MAX on failure.
+ * @param hStore The store which certificates should be counted.
+ */
+RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore);
+
RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch);
RTDECL(int) RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(RTCRSTORE hStore, PCRTCRX509NAME pSubject,
PRTCRSTORECERTSEARCH pSearch);
@@ -118,6 +351,13 @@ typedef struct RTCRCERTCTX
/** Extended certificate, DER encoded. */
#define RTCRCERTCTX_F_ENC_PKCS6_DER UINT32_C(0x00000002)
#endif
+/** Mask containing the flags that ends up in the certificate context. */
+#define RTCRCERTCTX_F_MASK UINT32_C(0x000000ff)
+
+/** Add APIs: Add the certificate if not found. */
+#define RTCRCERTCTX_F_ADD_IF_NOT_FOUND UINT32_C(0x00010000)
+/** Add APIs: Continue on error when possible. */
+#define RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR UINT32_C(0x00020000)
/** @} */
diff --git a/include/iprt/crypto/x509.h b/include/iprt/crypto/x509.h
index eb1957d..76dcd8e 100644
--- a/include/iprt/crypto/x509.h
+++ b/include/iprt/crypto/x509.h
@@ -164,7 +164,7 @@ RTDECL(bool) RTCrX509Name_ConstraintMatch(PCRTCRX509NAME pConstraint, PCRTCRX509
RTDECL(int) RTCrX509Name_RecodeAsUtf8(PRTCRX509NAME pThis, PCRTASN1ALLOCATORVTABLE pAllocator);
/**
- * Matches the directory name against a comma separated list of the comonent
+ * Matches the directory name against a comma separated list of the component
* strings (case sensitive).
*
* @returns true if match, false if mismatch.
diff --git a/include/iprt/dir.h b/include/iprt/dir.h
index 54e2359..1da18bf 100644
--- a/include/iprt/dir.h
+++ b/include/iprt/dir.h
@@ -229,7 +229,7 @@ typedef enum RTDIRFILTER
* Directory entry type.
*
* This is the RTFS_TYPE_MASK stuff shifted down 12 bits and
- * identical to the BSD/LINUX ABI.
+ * identical to the BSD/LINUX ABI. See RTFS_TYPE_DIRENTRYTYPE_SHIFT.
*/
typedef enum RTDIRENTRYTYPE
{
diff --git a/include/iprt/err.h b/include/iprt/err.h
index bbb2bbe..acba941 100644
--- a/include/iprt/err.h
+++ b/include/iprt/err.h
@@ -926,6 +926,10 @@ RT_C_DECLS_END
#define VWRN_UNABLE_TO_SATISFY_REQUIREMENTS 22406
/** The requested allocation is too big. */
#define VERR_ALLOCATION_TOO_BIG (-22407)
+/** Mismatch. */
+#define VERR_MISMATCH (-22408)
+/** Wrong type. */
+#define VERR_WRONG_TYPE (-22409)
/** @} */
@@ -1605,6 +1609,10 @@ RT_C_DECLS_END
#define VERR_CPU_OFFLINE (-800)
/** The specified cpu was not found. */
#define VERR_CPU_NOT_FOUND (-801)
+/** Not all of the requested CPUs showed up in the PFNRTMPWORKER. */
+#define VERR_NOT_ALL_CPUS_SHOWED (-802)
+/** Internal processing error in the RTMp code.*/
+#define VERR_CPU_IPE_1 (-803)
/** @} */
/** @name RTGetOpt status codes
@@ -1671,6 +1679,12 @@ RT_C_DECLS_END
#define VERR_HTTP_ABORTED (-893)
/** Request was redirected. */
#define VERR_HTTP_REDIRECTED (-894)
+/** Proxy couldn't be resolved. */
+#define VERR_HTTP_PROXY_NOT_FOUND (-895)
+/** Unexpected cURL error configure the proxy. */
+#define VERR_HTTP_CURL_PROXY_CONFIG (-897)
+/** Generic CURL error. */
+#define VERR_HTTP_CURL_ERROR (-899)
/** @} */
/** @name RTManifest status codes
@@ -2430,12 +2444,48 @@ RT_C_DECLS_END
/** @name RTCrDigest status codes.
* @{ */
-/** OpenSSL failed to initialize the digest algorithm contextn. */
+/** OpenSSL failed to initialize the digest algorithm context. */
#define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR (-24200)
/** OpenSSL failed to clone the digest algorithm contextn. */
#define VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR (-24201)
/** @} */
+/** @name RTPath status codes.
+ * @{ */
+/** Unknown glob variable. */
+#define VERR_PATH_MATCH_UNKNOWN_VARIABLE (-24400)
+/** The specified glob variable must be first in the pattern. */
+#define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST (-24401)
+/** Hit unimplemented glob pattern matching feature. */
+#define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED (-24402)
+/** Unknown character class in glob pattern. */
+#define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS (-24403)
+/** @} */
+
+/** @name RTUri status codes.
+ * @{ */
+/** The URI is empty */
+#define VERR_URI_EMPTY (-24600)
+/** The URI is too short to be a valid URI. */
+#define VERR_URI_TOO_SHORT (-24601)
+/** Invalid scheme. */
+#define VERR_URI_INVALID_SCHEME (-24602)
+/** Invalid port number. */
+#define VERR_URI_INVALID_PORT_NUMBER (-24603)
+/** Invalid escape sequence. */
+#define VERR_URI_INVALID_ESCAPE_SEQ (-24604)
+/** Escape URI char decodes as zero (the C string terminator). */
+#define VERR_URI_ESCAPED_ZERO (-24605)
+/** Escaped URI characters does not decode to valid UTF-8. */
+#define VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8 (-24606)
+/** Escaped URI character is not a valid UTF-8 lead byte. */
+#define VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE (-24607)
+/** Escaped URI character sequence with invalid UTF-8 continutation byte. */
+#define VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE (-24608)
+/** Missing UTF-8 continutation in escaped URI character sequence. */
+#define VERR_URI_MISSING_UTF8_CONTINUATION_BYTE (-24609)
+/** @} */
+
/* SED-END */
/** @} */
diff --git a/include/iprt/file.h b/include/iprt/file.h
index 616dace..4e7068b 100644
--- a/include/iprt/file.h
+++ b/include/iprt/file.h
@@ -706,6 +706,20 @@ RTDECL(int) RTFileCreateTemp(char *pszTemplate, RTFMODE fMode);
*/
RTDECL(int) RTFileCreateTempSecure(char *pszTemplate);
+/**
+ * Opens a new file with a unique name in the temp directory.
+ *
+ * @returns iprt status code.
+ * @param pszTemplate The file name template on input. The actual file
+ * name on success. Empty string on failure.
+ * @param fMode The mode to create the file with. Use 0600 unless
+ * you have reason not to.
+ *
+ * @remarks If actual control over the filename or location is required, we'll
+ * create an extended edition of this API.
+ */
+RTDECL(int) RTFileOpenTemp(PRTFILE pFile, char *pszFilename, size_t cbFilename, uint64_t fOpen);
+
/** @page pg_rt_filelock RT File locking API description
*
diff --git a/include/iprt/fs.h b/include/iprt/fs.h
index 3055bf4..b1b0b5b 100644
--- a/include/iprt/fs.h
+++ b/include/iprt/fs.h
@@ -116,6 +116,8 @@ RT_C_DECLS_BEGIN
#define RTFS_TYPE_WHITEOUT 0160000U
/** Type mask (S_IFMT). */
#define RTFS_TYPE_MASK 0170000U
+/** The shift count to convert between RTFS_TYPE_MASK and DIRENTRYTYPE. */
+#define RTFS_TYPE_DIRENTRYTYPE_SHIFT 12
/** Unix attribute mask. */
#define RTFS_UNIX_MASK 0xffffU
@@ -592,6 +594,17 @@ typedef RTFSPROPERTIES const *PCRTFSPROPERTIES;
*/
RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties);
+/**
+ * Checks if the given volume is case sensitive or not.
+ *
+ * This may be misleading in some cases as we lack the necessary APIs to query
+ * the information on some system (or choose not to use them) and are instead
+ * returning the general position on case sensitive file name of the system.
+ *
+ * @returns @c true if case sensitive, @c false if not.
+ * @param pszFsPath Path within the mounted file system.
+ */
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath);
/**
* Mountpoint enumerator callback.
diff --git a/include/iprt/http.h b/include/iprt/http.h
index 4dcb10a..37cc9dc 100644
--- a/include/iprt/http.h
+++ b/include/iprt/http.h
@@ -1,6 +1,6 @@
/* $Id: http.h $ */
/** @file
- * IPRT - Simple HTTP Communication API.
+ * IPRT - Simple HTTP/HTTPS Client API.
*/
/*
@@ -31,22 +31,22 @@
RT_C_DECLS_BEGIN
-/** @defgroup grp_rt_http RTHttp - Simple HTTP API
+/** @defgroup grp_rt_http RTHttp - Simple HTTP/HTTPS Client API
* @ingroup grp_rt
* @{
*/
/** @todo the following three definitions may move the iprt/types.h later. */
-/** RTHTTP interface handle. */
+/** HTTP/HTTPS client handle. */
typedef R3PTRTYPE(struct RTHTTPINTERNAL *) RTHTTP;
-/** Pointer to a RTHTTP interface handle. */
-typedef RTHTTP *PRTHTTP;
-/** Nil RTHTTP interface handle. */
+/** Pointer to a HTTP/HTTPS client handle. */
+typedef RTHTTP *PRTHTTP;
+/** Nil HTTP/HTTPS client handle. */
#define NIL_RTHTTP ((RTHTTP)0)
/**
- * Creates a HTTP interface handle.
+ * Creates a HTTP client instance.
*
* @returns iprt status code.
*
@@ -55,7 +55,7 @@ typedef RTHTTP *PRTHTTP;
RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp);
/**
- * Destroys a HTTP interface handle.
+ * Destroys a HTTP client instance.
*
* @param hHttp Handle to the HTTP interface.
*/
@@ -65,8 +65,8 @@ RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp);
/**
* Retrieve the redir location for 301 responses.
*
- * @param hHttp Handle to the HTTP interface.
- * @para ppszRedirLocation Where to store the string. To be freed with
+ * @param hHttp Handle to the HTTP interface.
+ * @param ppszRedirLocation Where to store the string. To be freed with
* RTStrFree().
*/
RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation);
@@ -74,34 +74,66 @@ RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation);
/**
* Perform a simple blocking HTTP request.
*
+ * This is a just a convenient wrapper around RTHttpGetBinary that returns a
+ * different type and sheds a parameter.
+ *
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param pcszUrl URL.
- * @param ppszResponse HTTP response. It is guaranteed that this string is
- * '\0'-terminated.
+ * @param hHttp The HTTP client instance.
+ * @param pszUrl URL.
+ * @param ppszNotUtf8 Where to return the poitner to the HTTP response.
+ * The string is of course zero terminated. Use
+ * RTHttpFreeReponseText to free.
+ *
+ * @remarks BIG FAT WARNING!
+ *
+ * This function does not guarantee the that returned string is valid UTF-8 or
+ * any other kind of text encoding!
+ *
+ * The caller must determine and validate the string encoding _before_
+ * passing it along to functions that expect UTF-8!
+ *
+ * Also, this function does not guarantee that the returned string
+ * doesn't have embedded zeros and provides the caller no way of
+ * finding out! If you are worried about the response from the HTTPD
+ * containing embedded zero's, use RTHttpGetBinary instead.
*/
-RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse);
+RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8);
+
+/**
+ * Frees memory returned by RTHttpGetText.
+ *
+ * @param pszNotUtf8 What RTHttpGetText returned.
+ */
+RTR3DECL(void) RTHttpFreeResponseText(char *pszNotUtf8);
/**
* Perform a simple blocking HTTP request.
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param pcszUrl URL.
- * @param ppvResponse HTTP response.
- * @param pcb Size of the returned buffer.
+ * @param hHttp The HTTP client instance.
+ * @param pszUrl The URL.
+ * @param ppvResponse Where to store the HTTP response data. Use
+ * RTHttpFreeResponse to free.
+ * @param pcb Size of the returned buffer.
+ */
+RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb);
+
+/**
+ * Frees memory returned by RTHttpGetBinary.
+ *
+ * @param pvResponse What RTHttpGetBinary returned.
*/
-RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb);
+RTR3DECL(void) RTHttpFreeResponse(void *pvResponse);
/**
* Perform a simple blocking HTTP request, writing the output to a file.
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param pszUrl URL.
+ * @param hHttp The HTTP client instance.
+ * @param pszUrl The URL.
* @param pszDstFile The destination file name.
*/
RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile);
@@ -113,7 +145,7 @@ RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDst
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
+ * @param hHttp The HTTP client instance.
*/
RTR3DECL(int) RTHttpAbort(RTHTTP hHttp);
@@ -121,7 +153,7 @@ RTR3DECL(int) RTHttpAbort(RTHTTP hHttp);
* Tells the HTTP interface to use the system proxy configuration.
*
* @returns iprt status code.
- * @param hHttp HTTP interface handle.
+ * @param hHttp The HTTP client instance.
*/
RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp);
@@ -130,58 +162,80 @@ RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp);
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param pcszProxy URL of the proxy
- * @param uPort port number of the proxy, use 0 for not specifying a port.
- * @param pcszUser username, pass NULL for no authentication
- * @param pcszPwd password, pass NULL for no authentication
+ * @param hHttp The HTTP client instance.
+ * @param pszProxy URL of the proxy.
+ * @param uPort port number of the proxy, use 0 for not specifying a port.
+ * @param pszProxyUser Username, pass NULL for no authentication.
+ * @param pszProxyPwd Password, pass NULL for no authentication.
*/
-RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxyUrl, uint32_t uPort,
- const char *pcszProxyUser, const char *pcszProxyPwd);
+RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pszProxyUrl, uint32_t uPort,
+ const char *pszProxyUser, const char *pszProxyPwd);
/**
* Set custom headers.
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param cHeaders number of custom headers.
- * @param pcszHeaders array of headers in form "foo: bar".
+ * @param hHttp The HTTP client instance.
+ * @param cHeaders Number of custom headers.
+ * @param papszHeaders Array of headers in form "foo: bar".
*/
RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders);
/**
+ * Tells the HTTP client instance to gather system CA certificates into a
+ * temporary file and use it for HTTPS connections.
+ *
+ * This will be called automatically if a 'https' URL is presented and
+ * RTHttpSetCaFile hasn't been called yet.
+ *
+ * @returns IPRT status code.
+ * @param hHttp The HTTP client instance.
+ * @param pErrInfo Where to store additional error/warning information.
+ * Optional.
+ */
+RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo);
+
+/**
* Set a custom certification authority file, containing root certificates.
*
* @returns iprt status code.
*
- * @param hHttp HTTP interface handle.
- * @param pcszCAFile File name containing root certificates.
+ * @param hHttp The HTTP client instance.
+ * @param pszCAFile File name containing root certificates.
+ *
+ * @remarks For portable HTTPS support, use RTHttpGatherCaCertsInFile and pass
*/
-RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile);
-
+RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCAFile);
/**
- * Determine the digest (fingerprint) of a certificate. Allocate memory for
- * storing the SHA1 fingerprint as well as the SHA512 fingerprint. This
- * memory has to be freed by RTMemFree().
- *
- * @todo Move this function to somewhere else.
+ * Gathers certificates into a cryptographic (certificate) store
*
- * @returns iprt status code.
+ * This is a just a combination of RTHttpGatherCaCertsInStore and
+ * RTCrStoreCertExportAsPem.
*
- * @param hHttp HTTP interface handle (ignored).
- * @param pcszCert The certificate in PEM format.
- * @param cbCert Size of the certificate.
- * @param pabSha1 Where to store the pointer to the SHA1 fingerprint.
- * @param pcbSha1 Where to store the size of the SHA1 fingerprint.
- * @param pabSha512 Where to store the pointer to the SHA512 fingerprint.
- * @param pcbSha512 Where to store the size of the SHA512 fingerprint.
+ * @returns IPRT status code.
+ * @param hStore The certificate store to gather the certificates
+ * in.
+ * @param fFlags RTHTTPGATHERCACERT_F_XXX.
+ * @param pErrInfo Where to store additional error/warning information.
+ * Optional.
*/
-RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert,
- uint8_t **pabSha1, size_t *pcbSha1,
- uint8_t **pabSha512, size_t *pcbSha512);
+RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo);
+/**
+ * Gathers certificates into a file that can be used with RTHttpSetCAFile.
+ *
+ * This is a just a combination of RTHttpGatherCaCertsInStore and
+ * RTCrStoreCertExportAsPem.
+ *
+ * @returns IPRT status code.
+ * @param pszCaFile The output file.
+ * @param fFlags RTHTTPGATHERCACERT_F_XXX.
+ * @param pErrInfo Where to store additional error/warning information.
+ * Optional.
+ */
+RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo);
/** @} */
diff --git a/include/iprt/log.h b/include/iprt/log.h
index 6cf1637..393d2be 100644
--- a/include/iprt/log.h
+++ b/include/iprt/log.h
@@ -52,11 +52,13 @@ typedef enum RTLOGGROUP
{
/** Default logging group. */
RTLOGGROUP_DEFAULT,
+ RTLOGGROUP_CRYPTO,
RTLOGGROUP_DBG,
RTLOGGROUP_DBG_DWARF,
RTLOGGROUP_DIR,
RTLOGGROUP_FILE,
RTLOGGROUP_FS,
+ RTLOGGROUP_HTTP,
RTLOGGROUP_LDR,
RTLOGGROUP_PATH,
RTLOGGROUP_PROCESS,
@@ -83,11 +85,13 @@ typedef enum RTLOGGROUP
*/
#define RT_LOGGROUP_NAMES \
"DEFAULT", \
+ "RT_CRYPTO", \
"RT_DBG", \
"RT_DBG_DWARF", \
"RT_DIR", \
"RT_FILE", \
"RT_FS", \
+ "RT_HTTP", \
"RT_LDR", \
"RT_PATH", \
"RT_PROCESS", \
@@ -95,8 +99,6 @@ typedef enum RTLOGGROUP
"RT_THREAD", \
"RT_TIME", \
"RT_TIMER", \
- "RT_13", \
- "RT_14", \
"RT_15", \
"RT_16", \
"RT_17", \
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
index 6b6fcb0..f2ec467 100644
--- a/include/iprt/mangling.h
+++ b/include/iprt/mangling.h
@@ -576,6 +576,7 @@
# define RTFileOpenBitBucket RT_MANGLER(RTFileOpenBitBucket)
# define RTFileOpenF RT_MANGLER(RTFileOpenF)
# define RTFileOpenV RT_MANGLER(RTFileOpenV)
+# define RTFileOpenTemp RT_MANGLER(RTFileOpenTemp)
# define RTFileQueryFsSizes RT_MANGLER(RTFileQueryFsSizes)
# define RTFileQueryInfo RT_MANGLER(RTFileQueryInfo)
# define RTFileQuerySize RT_MANGLER(RTFileQuerySize)
@@ -601,6 +602,7 @@
# define RTFileWrite RT_MANGLER(RTFileWrite)
# define RTFileWriteAt RT_MANGLER(RTFileWriteAt)
# define RTFilesystemVfsFromFile RT_MANGLER(RTFilesystemVfsFromFile)
+# define RTFsIsCaseSensitive RT_MANGLER(RTFsIsCaseSensitive)
# define RTFsQueryProperties RT_MANGLER(RTFsQueryProperties)
# define RTFsQuerySerial RT_MANGLER(RTFsQuerySerial)
# define RTFsQuerySizes RT_MANGLER(RTFsQuerySizes)
@@ -1010,6 +1012,7 @@
# define RTPathCompare RT_MANGLER(RTPathCompare)
# define RTPathCopyComponents RT_MANGLER(RTPathCopyComponents)
# define RTPathCountComponents RT_MANGLER(RTPathCountComponents)
+# define RTPathEnsureTrailingSeparator RT_MANGLER(RTPathEnsureTrailingSeparator)
# define RTPathExecDir RT_MANGLER(RTPathExecDir)
# define RTPathExists RT_MANGLER(RTPathExists)
# define RTPathExistsEx RT_MANGLER(RTPathExistsEx)
@@ -1021,6 +1024,8 @@
# define RTPathGetCurrentOnDrive RT_MANGLER(RTPathGetCurrentOnDrive)
# define RTPathGetMode RT_MANGLER(RTPathGetMode)
# define RTPathHasExt RT_MANGLER(RTPathHasExt)
+# define RTPathGlob RT_MANGLER(RTPathGlob)
+# define RTPathGlobFree RT_MANGLER(RTPathGlobFree)
# define RTPathHasPath RT_MANGLER(RTPathHasPath)
# define RTPathIsSame RT_MANGLER(RTPathIsSame)
# define RTPathJoin RT_MANGLER(RTPathJoin)
@@ -1303,6 +1308,7 @@
# define RTSgBufSet RT_MANGLER(RTSgBufSet)
# define RTSgBufGetNextSegment RT_MANGLER(RTSgBufGetNextSegment)
# define RTSha1 RT_MANGLER(RTSha1)
+# define RTSha1Check RT_MANGLER(RTSha1Check)
# define RTSha1Digest RT_MANGLER(RTSha1Digest)
# define RTSha1DigestFromFile RT_MANGLER(RTSha1DigestFromFile)
# define RTSha1Final RT_MANGLER(RTSha1Final)
@@ -1311,6 +1317,7 @@
# define RTSha1ToString RT_MANGLER(RTSha1ToString)
# define RTSha1Update RT_MANGLER(RTSha1Update)
# define RTSha224 RT_MANGLER(RTSha224)
+# define RTSha224Check RT_MANGLER(RTSha224Check)
# define RTSha224Final RT_MANGLER(RTSha224Final)
# define RTSha224FromString RT_MANGLER(RTSha224FromString)
# define RTSha224Init RT_MANGLER(RTSha224Init)
@@ -1319,6 +1326,7 @@
# define RTSha224Digest RT_MANGLER(RTSha224Digest)
# define RTSha224DigestFromFile RT_MANGLER(RTSha224DigestFromFile)
# define RTSha256 RT_MANGLER(RTSha256)
+# define RTSha256Check RT_MANGLER(RTSha256Check)
# define RTSha256Final RT_MANGLER(RTSha256Final)
# define RTSha256FromString RT_MANGLER(RTSha256FromString)
# define RTSha256Init RT_MANGLER(RTSha256Init)
@@ -1327,24 +1335,28 @@
# define RTSha256Digest RT_MANGLER(RTSha256Digest)
# define RTSha256DigestFromFile RT_MANGLER(RTSha256DigestFromFile)
# define RTSha384 RT_MANGLER(RTSha384)
+# define RTSha384Check RT_MANGLER(RTSha384Check)
# define RTSha384Final RT_MANGLER(RTSha384Final)
# define RTSha384FromString RT_MANGLER(RTSha384FromString)
# define RTSha384Init RT_MANGLER(RTSha384Init)
# define RTSha384ToString RT_MANGLER(RTSha384ToString)
# define RTSha384Update RT_MANGLER(RTSha384Update)
# define RTSha512 RT_MANGLER(RTSha512)
+# define RTSha512Check RT_MANGLER(RTSha512Check)
# define RTSha512Final RT_MANGLER(RTSha512Final)
# define RTSha512FromString RT_MANGLER(RTSha512FromString)
# define RTSha512Init RT_MANGLER(RTSha512Init)
# define RTSha512ToString RT_MANGLER(RTSha512ToString)
# define RTSha512Update RT_MANGLER(RTSha512Update)
# define RTSha512t224 RT_MANGLER(RTSha512t224)
+# define RTSha512t224Check RT_MANGLER(RTSha512t224Check)
# define RTSha512t224Final RT_MANGLER(RTSha512t224Final)
# define RTSha512t224FromString RT_MANGLER(RTSha512t224FromString)
# define RTSha512t224Init RT_MANGLER(RTSha512t224Init)
# define RTSha512t224ToString RT_MANGLER(RTSha512t224ToString)
# define RTSha512t224Update RT_MANGLER(RTSha512t224Update)
# define RTSha512t256 RT_MANGLER(RTSha512t256)
+# define RTSha512t256Check RT_MANGLER(RTSha512t256Check)
# define RTSha512t256Final RT_MANGLER(RTSha512t256Final)
# define RTSha512t256FromString RT_MANGLER(RTSha512t256FromString)
# define RTSha512t256Init RT_MANGLER(RTSha512t256Init)
@@ -1790,16 +1802,22 @@
# define RTUdpServerShutdown RT_MANGLER(RTUdpServerShutdown)
# define RTUdpWrite RT_MANGLER(RTUdpWrite)
# define RTUniFree RT_MANGLER(RTUniFree)
-# define RTUriAuthority RT_MANGLER(RTUriAuthority)
# define RTUriCreate RT_MANGLER(RTUriCreate)
# define RTUriFileCreate RT_MANGLER(RTUriFileCreate)
# define RTUriFileNPath RT_MANGLER(RTUriFileNPath)
# define RTUriFilePath RT_MANGLER(RTUriFilePath)
-# define RTUriFragment RT_MANGLER(RTUriFragment)
-# define RTUriHasScheme RT_MANGLER(RTUriHasScheme)
+# define RTUriParse RT_MANGLER(RTUriParse)
+# define RTUriParsedAuthority RT_MANGLER(RTUriParsedAuthority)
+# define RTUriParsedAuthorityHost RT_MANGLER(RTUriParsedAuthorityHost)
+# define RTUriParsedAuthorityPassword RT_MANGLER(RTUriParsedAuthorityPassword)
+# define RTUriParsedAuthorityPort RT_MANGLER(RTUriParsedAuthorityPort)
+# define RTUriParsedAuthorityUsername RT_MANGLER(RTUriParsedAuthorityUsername)
+# define RTUriParsedFragment RT_MANGLER(RTUriParsedFragment)
+# define RTUriParsedPath RT_MANGLER(RTUriParsedPath)
+# define RTUriParsedScheme RT_MANGLER(RTUriParsedScheme)
+# define RTUriParsedQuery RT_MANGLER(RTUriParsedQuery)
+# define RTUriIsSchemeMatch RT_MANGLER(RTUriIsSchemeMatch)
# define RTUriPath RT_MANGLER(RTUriPath)
-# define RTUriQuery RT_MANGLER(RTUriQuery)
-# define RTUriScheme RT_MANGLER(RTUriScheme)
# define RTUtf16AllocTag RT_MANGLER(RTUtf16AllocTag)
# define RTUtf16CalcLatin1Len RT_MANGLER(RTUtf16CalcLatin1Len)
# define RTUtf16CalcLatin1LenEx RT_MANGLER(RTUtf16CalcLatin1LenEx)
@@ -2367,6 +2385,7 @@
# define RTCrRsaPrivateKey_CheckSanity RT_MANGLER(RTCrRsaPrivateKey_CheckSanity)
# define RTCrRsaPublicKey_CheckSanity RT_MANGLER(RTCrRsaPublicKey_CheckSanity)
# define RTCrPemFreeSections RT_MANGLER(RTCrPemFreeSections)
+# define RTCrPemParseContent RT_MANGLER(RTCrPemParseContent)
# define RTCrPemReadFile RT_MANGLER(RTCrPemReadFile)
# define RTCrPkcs7Attribute_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attribute_DecodeAsn1)
# define RTCrPkcs7Attributes_DecodeAsn1 RT_MANGLER(RTCrPkcs7Attributes_DecodeAsn1)
@@ -2825,6 +2844,7 @@
# define RTCrCertCtxRetain RT_MANGLER(RTCrCertCtxRetain)
# define RTCrStoreCertAddEncoded RT_MANGLER(RTCrStoreCertAddEncoded)
# define RTCrStoreCertByIssuerAndSerialNo RT_MANGLER(RTCrStoreCertByIssuerAndSerialNo)
+# define RTCrStoreCertCount RT_MANGLER(RTCrStoreCertCount)
# define RTCrStoreCertFindAll RT_MANGLER(RTCrStoreCertFindAll)
# define RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280)
# define RTCrStoreCertSearchDestroy RT_MANGLER(RTCrStoreCertSearchDestroy)
@@ -2834,7 +2854,18 @@
# define RTCrStoreRelease RT_MANGLER(RTCrStoreRelease)
# define RTCrStoreRetain RT_MANGLER(RTCrStoreRetain)
# define RTCrStoreCreateInMem RT_MANGLER(RTCrStoreCreateInMem)
+# define RTCrStoreCreateSnapshotById RT_MANGLER(RTCrStoreCreateSnapshotById)
+# define RTCrStoreCertAddFromDir RT_MANGLER(RTCrStoreCertAddFromDir)
# define RTCrStoreCertAddFromFile RT_MANGLER(RTCrStoreCertAddFromFile)
+# define RTCrStoreCertAddFromJavaKeyStore RT_MANGLER(RTCrStoreCertAddFromJavaKeyStore)
+# define RTCrStoreCertAddFromJavaKeyStoreInMem RT_MANGLER(RTCrStoreCertAddFromJavaKeyStoreInMem)
+# define RTCrStoreCertAddFromStore RT_MANGLER(RTCrStoreCertAddFromStore)
+# define RTCrStoreCertAddWantedFromDir RT_MANGLER(RTCrStoreCertAddWantedFromDir)
+# define RTCrStoreCertAddWantedFromFile RT_MANGLER(RTCrStoreCertAddWantedFromFile)
+# define RTCrStoreCertAddWantedFromStore RT_MANGLER(RTCrStoreCertAddWantedFromStore)
+# define RTCrStoreCertAddWantedFromFishingExpedition RT_MANGLER(RTCrStoreCertAddWantedFromFishingExpedition)
+# define RTCrStoreCertCheckWanted RT_MANGLER(RTCrStoreCertCheckWanted)
+# define RTCrStoreCertExportAsPem RT_MANGLER(RTCrStoreCertExportAsPem)
# define RTErrInfoAdd RT_MANGLER(RTErrInfoAdd)
# define RTErrInfoAddF RT_MANGLER(RTErrInfoAddF)
# define RTErrInfoAddV RT_MANGLER(RTErrInfoAddV)
diff --git a/include/iprt/mp.h b/include/iprt/mp.h
index 23ababc..80724ed 100644
--- a/include/iprt/mp.h
+++ b/include/iprt/mp.h
@@ -244,6 +244,18 @@ typedef DECLCALLBACK(void) FNRTMPWORKER(RTCPUID idCpu, void *pvUser1, void *pvUs
/** Pointer to a FNRTMPWORKER. */
typedef FNRTMPWORKER *PFNRTMPWORKER;
+/** @name RTMPON_F_XXX - RTMpOn flags.
+ * @{ */
+/** Caller doesn't care if pfnWorker is executed at the same time on the
+ * specified CPUs or not, as long as it gets executed. */
+#define RTMPON_F_WHATEVER_EXEC 0
+/** The caller insists on pfnWorker being executed more or less concurrently
+ * on the specified CPUs. */
+#define RTMPON_F_CONCURRENT_EXEC RT_BIT_32(1)
+/** Mask of valid bits. */
+#define RTMPON_F_VALID_MASK UINT32_C(0x00000001)
+/** @}*/
+
/**
* Executes a function on each (online) CPU in the system.
*
@@ -296,6 +308,40 @@ RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
/**
+ * Executes a function on two specific CPUs in the system.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_NOT_SUPPORTED if this kind of operation isn't supported by the
+ * system or if the specified modifier flag isn't supported.
+ * @retval VERR_CPU_OFFLINE if one or more of the CPUs are offline (see
+ * remarks).
+ * @retval VERR_CPU_NOT_FOUND if on or both of the CPUs weren't found.
+ * @retval VERR_NOT_ALL_CPUS_SHOWED if one of the CPUs didn't show.
+ *
+ * @param idCpu1 The id of the first CPU.
+ * @param idCpu2 The id of the second CPU.
+ * @param fFlags Combination of RTMPON_F_XXX flags.
+ * @param pfnWorker The worker function.
+ * @param pvUser1 The first user argument for the worker.
+ * @param pvUser2 The second user argument for the worker.
+ *
+ * @remarks There is a possible race between one (or both) of the CPUs going
+ * offline while setting up the call. The worker function must take
+ * this into account.
+ */
+RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2);
+
+/**
+ * Indicates whether RTMpOnPair supports running the pfnWorker concurrently on
+ * both CPUs using RTMPON_F_CONCURRENT_EXEC.
+ *
+ * @returns true if supported, false if not.
+ */
+RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void);
+
+
+/**
* Pokes the specified CPU.
*
* This should cause the execution on the CPU to be interrupted and forcing it
diff --git a/include/iprt/path.h b/include/iprt/path.h
index d147d95..a6fb059 100644
--- a/include/iprt/path.h
+++ b/include/iprt/path.h
@@ -358,6 +358,21 @@ RTDECL(void) RTPathStripExt(char *pszPath);
RTDECL(size_t) RTPathStripTrailingSlash(char *pszPath);
/**
+ * Ensures that the path has a trailing path separator such that file names can
+ * be appended without further work.
+ *
+ * This can be helpful when preparing for efficiently combining a directory path
+ * with the filenames returned by RTDirRead. The return value gives you the
+ * position at which you copy the RTDIRENTRY::szName to construct a valid path
+ * to it.
+ *
+ * @returns The length of the path, 0 on buffer overflow.
+ * @param pszPath The path.
+ * @param cbPath The length of the path buffer @a pszPath points to.
+ */
+RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath);
+
+/**
* Changes all the slashes in the specified path to DOS style.
*
* Unless @a fForce is set, nothing will be done when on a UNIX flavored system
@@ -582,7 +597,7 @@ RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc,
*
* The first component is the root, volume or UNC specifier, if present. Use
* RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its
- * precense.
+ * presence.
*
* Other than the root component, no component will include directory separators
* (slashes).
@@ -1153,6 +1168,72 @@ RTDECL(int) RTPathAppDocs(char *pszPath, size_t cchPath);
*/
RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath);
+
+/**
+ * RTPathGlobl result entry.
+ */
+typedef struct RTPATHGLOBENTRY
+{
+ /** List entry. */
+ struct RTPATHGLOBENTRY *pNext;
+ /** RTDIRENTRYTYPE value. */
+ uint8_t uType;
+ /** Unused explicit padding. */
+ uint8_t bUnused;
+ /** The length of the path. */
+ uint16_t cchPath;
+ /** The path to the file (variable length). */
+ char szPath[1];
+} RTPATHGLOBENTRY;
+/** Pointer to a GLOB result entry. */
+typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY;
+/** Pointer to a const GLOB result entry. */
+typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY;
+/** Pointer to a GLOB result entry pointer. */
+typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY;
+
+/**
+ * Performs wildcard expansion on a path pattern.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pszPattern The pattern to expand.
+ * @param fFlags RTPATHGLOB_F_XXX.
+ * @param ppHead Where to return the head of the result list. This
+ * is always set to NULL on failure.
+ * @param pcResults Where to return the number of the result. Optional.
+ */
+RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults);
+
+/** @name RTPATHGLOB_F_XXX - RTPathGlob flags
+ * @{ */
+/** Case insensitive. */
+#define RTPATHGLOB_F_IGNORE_CASE RT_BIT_32(0)
+/** Do not expand \${EnvOrSpecialVariable} in the pattern. */
+#define RTPATHGLOB_F_NO_VARIABLES RT_BIT_32(1)
+/** Do not interpret a leading tilde as a home directory reference. */
+#define RTPATHGLOB_F_NO_TILDE RT_BIT_32(2)
+/** Only return the first match. */
+#define RTPATHGLOB_F_FIRST_ONLY RT_BIT_32(3)
+/** Only match directories (implied if pattern ends with slash). */
+#define RTPATHGLOB_F_ONLY_DIRS RT_BIT_32(4)
+/** Do not match directories. (Can't be used with RTPATHGLOB_F_ONLY_DIRS or
+ * patterns containing a trailing slash.) */
+#define RTPATHGLOB_F_NO_DIRS RT_BIT_32(5)
+/** Disables the '**' wildcard pattern for matching zero or more subdirs. */
+#define RTPATHGLOB_F_NO_STARSTAR RT_BIT_32(6)
+/** Mask of valid flags. */
+#define RTPATHGLOB_F_MASK UINT32_C(0x0000007f)
+/** @} */
+
+/**
+ * Frees the results produced by RTPathGlob.
+ *
+ * @param pHead What RTPathGlob returned. NULL ignored.
+ */
+RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead);
+
+
/**
* Query information about a file system object.
*
diff --git a/include/iprt/sha.h b/include/iprt/sha.h
index a6c7391..2127b51 100644
--- a/include/iprt/sha.h
+++ b/include/iprt/sha.h
@@ -68,6 +68,17 @@ typedef RTSHA1CONTEXT *PRTSHA1CONTEXT;
RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA1_HASH_SIZE]);
/**
+ * Computes the SHA-1 hash for the given data comparing it with the one given.
+ *
+ * @returns true on match, false on mismatch.
+ * @param pvBuf Pointer to the data.
+ * @param cbBuf The amount of data (in bytes).
+ * @param pabHash The hash to verify. (What is passed is a pointer to the
+ * caller's buffer.)
+ */
+RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA1_HASH_SIZE]);
+
+/**
* Initializes the SHA-1 context.
*
* @param pCtx Pointer to the SHA-1 context.
@@ -176,6 +187,17 @@ typedef RTSHA256CONTEXT *PRTSHA256CONTEXT;
RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA256_HASH_SIZE]);
/**
+ * Computes the SHA-256 hash for the given data comparing it with the one given.
+ *
+ * @returns true on match, false on mismatch.
+ * @param pvBuf Pointer to the data.
+ * @param cbBuf The amount of data (in bytes).
+ * @param pabHash The hash to verify. (What is passed is a pointer to the
+ * caller's buffer.)
+ */
+RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA256_HASH_SIZE]);
+
+/**
* Initializes the SHA-256 context.
*
* @param pCtx Pointer to the SHA-256 context.
@@ -274,6 +296,17 @@ typedef RTSHA256CONTEXT *PRTSHA224CONTEXT;
RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA224_HASH_SIZE]);
/**
+ * Computes the SHA-224 hash for the given data comparing it with the one given.
+ *
+ * @returns true on match, false on mismatch.
+ * @param pvBuf Pointer to the data.
+ * @param cbBuf The amount of data (in bytes).
+ * @param pabHash The hash to verify. (What is passed is a pointer to the
+ * caller's buffer.)
+ */
+RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA224_HASH_SIZE]);
+
+/**
* Initializes the SHA-224 context.
*
* @param pCtx Pointer to the SHA-224 context.
@@ -382,6 +415,17 @@ typedef RTSHA512CONTEXT *PRTSHA512CONTEXT;
RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA512_HASH_SIZE]);
/**
+ * Computes the SHA-512 hash for the given data comparing it with the one given.
+ *
+ * @returns true on match, false on mismatch.
+ * @param pvBuf Pointer to the data.
+ * @param cbBuf The amount of data (in bytes).
+ * @param pabHash The hash to verify. (What is passed is a pointer to the
+ * caller's buffer.)
+ */
+RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA512_HASH_SIZE]);
+
+/**
* Initializes the SHA-512 context.
*
* @param pCtx Pointer to the SHA-512 context.
@@ -437,6 +481,7 @@ RTDECL(int) RTSha512FromString(char const *pszDigest, uint8_t pabDigest[RTSHA512
typedef RTSHA512CONTEXT RT_CONCAT3(RTSHA,a_UName,CONTEXT); \
typedef RTSHA512CONTEXT *RT_CONCAT3(PRTSHA,a_UName,CONTEXT); \
RTDECL(void) RT_CONCAT(RTSha,a_Name)(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \
+ RTDECL(bool) RT_CONCAT3(RTSha,a_Name,Check)(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \
RTDECL(void) RT_CONCAT3(RTSha,a_Name,Init)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx); \
RTDECL(void) RT_CONCAT3(RTSha,a_Name,Update)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf); \
RTDECL(void) RT_CONCAT3(RTSha,a_Name,Final)(RT_CONCAT3(PRTSHA,a_UName,CONTEXT) pCtx, uint8_t pabDigest[RT_CONCAT3(RTSHA,a_UName,_HASH_SIZE)]); \
diff --git a/include/iprt/string.h b/include/iprt/string.h
index 60d2346..daf88d0 100644
--- a/include/iprt/string.h
+++ b/include/iprt/string.h
@@ -107,6 +107,13 @@ char *strpbrk(const char *pszStr, const char *pszChars);
RT_C_DECLS_END
#endif
+#if !defined(RT_OS_LINUX) || !defined(_GNU_SOURCE)
+RT_C_DECLS_BEGIN
+void *memrchr(const char *pv, int ch, size_t cb);
+RT_C_DECLS_END
+#endif
+
+
/** @def RT_USE_RTC_3629
* When defined the UTF-8 range will stop at 0x10ffff. If not defined, the
* range stops at 0x7fffffff.
@@ -2526,6 +2533,24 @@ DECLINLINE(char *) RTStrEnd(const char *pszString, size_t cchMax)
RT_C_DECLS_BEGIN
/**
+ * Finds the offset at which a simple character first occurs in a string.
+ *
+ * @returns The offset of the first occurence or the terminator offset.
+ * @param pszHaystack The string to search.
+ * @param chNeedle The character to search for.
+ */
+DECLINLINE(size_t) RTStrOffCharOrTerm(const char *pszHaystack, char chNeedle)
+{
+ const char *psz = pszHaystack;
+ char ch;
+ while ( (ch = *psz) != chNeedle
+ && ch != '\0')
+ psz++;
+ return psz - pszHaystack;
+}
+
+
+/**
* Matches a simple string pattern.
*
* @returns true if the string matches the pattern, otherwise false.
diff --git a/include/iprt/types.h b/include/iprt/types.h
index cac8de9..dee2257 100644
--- a/include/iprt/types.h
+++ b/include/iprt/types.h
@@ -2180,6 +2180,21 @@ typedef const RTUTF16 *PCRTUTF16;
/**
+ * String tuple to go with the RT_STR_TUPLE macro.
+ */
+typedef struct RTSTRTUPLE
+{
+ /** The string. */
+ const char *psz;
+ /** The string length. */
+ size_t cch;
+} RTSTRTUPLE;
+/** Pointer to a string tuple. */
+typedef RTSTRTUPLE *PRTSTRTUPLE;
+/** Pointer to a const string tuple. */
+typedef RTSTRTUPLE const *PCRTSTRTUPLE;
+
+/**
* Wait for ever if we have to.
*/
#define RT_INDEFINITE_WAIT (~0U)
diff --git a/include/iprt/uri.h b/include/iprt/uri.h
index 5696e5a..c9d81e0 100644
--- a/include/iprt/uri.h
+++ b/include/iprt/uri.h
@@ -32,86 +32,248 @@
RT_C_DECLS_BEGIN
/** @defgroup grp_rt_uri RTUri - Uri parsing and creation
- * URI parsing and creation based on RFC 3986.
- * See http://datatracker.ietf.org/doc/rfc3986/ for the full specification.
- * @note Currently it isn't the full specification implemented.
- * @note Currently only some generic URI support and a minimum File(file:) URI
- * support is implemented. Other specific scheme support, like html:, ldap:,
- * data:, ..., is missing.
- * @see grp_rt_uri_file
+ *
+ * URI parsing and creation based on RFC-3986.
+ *
+ * @remarks The whole specification isn't implemented and we only provide scheme
+ * specific special APIs for "file://".
+ *
* @ingroup grp_rt
* @{
*/
+
/**
- * Creates a generic URI.
+ * Parsed URI.
*
- * @returns the new URI on success, NULL otherwise.
- * @param pszScheme The URI scheme.
- * @param pszAuthority The authority part of the URI (optional).
- * @param pszPath The path part of the URI (optional).
- * @param pszQuery The query part of the URI (optional).
- * @param pszFragment The fragment part of the URI (optional).
+ * @remarks This structure is subject to change.
*/
-RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment);
+typedef struct RTURIPARSED
+{
+ /** Magic value (for internal use only). */
+ uint32_t u32Magic;
+ /** RTURIPARSED_F_XXX. */
+ uint32_t fFlags;
+
+ /** The length of the scheme. */
+ size_t cchScheme;
+
+ /** The offset into the string of the authority. */
+ size_t offAuthority;
+ /** The authority length.
+ * @remarks The authority component can be zero length, so to check whether
+ * it's there or not consult RTURIPARSED_F_HAVE_AUTHORITY. */
+ size_t cchAuthority;
+
+ /** The offset into the string of the path. */
+ size_t offPath;
+ /** The length of the path. */
+ size_t cchPath;
+
+ /** The offset into the string of the query. */
+ size_t offQuery;
+ /** The length of the query. */
+ size_t cchQuery;
+
+ /** The offset into the string of the fragment. */
+ size_t offFragment;
+ /** The length of the fragment. */
+ size_t cchFragment;
+
+ /** @name Authority subdivisions
+ * @{ */
+ /** If there is a userinfo part, this is the start of it. Otherwise it's the
+ * same as offAuthorityHost. */
+ size_t offAuthorityUsername;
+ /** The length of the username (zero if not present). */
+ size_t cchAuthorityUsername;
+ /** If there is a userinfo part containing a password, this is the start of it.
+ * Otherwise it's the same as offAuthorityHost. */
+ size_t offAuthorityPassword;
+ /** The length of the password (zero if not present). */
+ size_t cchAuthorityPassword;
+ /** The offset of the host part of the authority. */
+ size_t offAuthorityHost;
+ /** The length of the host part of the authority. */
+ size_t cchAuthorityHost;
+ /** The authority port number, UINT32_MAX if not present. */
+ uint32_t uAuthorityPort;
+ /** @} */
+} RTURIPARSED;
+/** Pointer to a parsed URI. */
+typedef RTURIPARSED *PRTURIPARSED;
+/** Pointer to a const parsed URI. */
+typedef RTURIPARSED const *PCRTURIPARSED;
+
+/** @name RTURIPARSED_F_XXX - RTURIPARSED::fFlags
+ * @{ */
+/** Set if the URI contains escaped characters. */
+#define RTURIPARSED_F_CONTAINS_ESCAPED_CHARS UINT32_C(0x00000001)
+/** Set if the URI have an authority component. Necessary since the authority
+ * component can have a zero length. */
+#define RTURIPARSED_F_HAVE_AUTHORITY UINT32_C(0x00000002)
+/** @} */
/**
- * Check an string for a specific URI scheme.
+ * Parses a URI.
*
- * @returns true if the scheme match, false if not.
- * @param pszUri The URI to check.
- * @param pszScheme The scheme to compare with.
+ * @returns IPRT status code.
+ * @param pszUri The URI to parse.
+ * @param pParsed Where to return the details. This can be handed
+ * to the RTUriParsed* APIs for retriving
+ * information.
*/
-RTR3DECL(bool) RTUriHasScheme(const char *pszUri, const char *pszScheme);
+RTDECL(int) RTUriParse(const char *pszUri, PRTURIPARSED pParsed);
/**
- * Extract the scheme out of an URI.
+ * Extract the scheme out of a parsed URI.
*
* @returns the scheme if the URI is valid, NULL otherwise.
- * @param pszUri The URI to extract from.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
*/
-RTR3DECL(char *) RTUriScheme(const char *pszUri);
+RTDECL(char *) RTUriParsedScheme(const char *pszUri, PCRTURIPARSED pParsed);
/**
- * Extract the authority out of an URI.
+ * Extract the authority out of a parsed URI.
*
* @returns the authority if the URI contains one, NULL otherwise.
- * @param pszUri The URI to extract from.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ * @remarks The authority can have a zero length.
*/
-RTR3DECL(char *) RTUriAuthority(const char *pszUri);
+RTDECL(char *) RTUriParsedAuthority(const char *pszUri, PCRTURIPARSED pParsed);
/**
- * Extract the path out of an URI.
+ * Extract the username out of the authority component in a parsed URI.
+ *
+ * @returns The username if the URI contains one, otherwise NULL.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ *
+ * @todo This may currently be returning NULL when it maybe would be more
+ * appropriate to return an empty string...
+ */
+RTDECL(char *) RTUriParsedAuthorityUsername(const char *pszUri, PCRTURIPARSED pParsed);
+
+/**
+ * Extract the password out of the authority component in a parsed URI.
+ *
+ * @returns The password if the URI contains one, otherwise NULL.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ *
+ * @todo This may currently be returning NULL when it maybe would be more
+ * appropriate to return an empty string...
+ */
+RTDECL(char *) RTUriParsedAuthorityPassword(const char *pszUri, PCRTURIPARSED pParsed);
+
+/**
+ * Extract the host out of the authority component in a parsed URI.
+ *
+ * @returns The host if the URI contains one, otherwise NULL.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ *
+ * @todo This may currently be returning NULL when it maybe would be more
+ * appropriate to return an empty string...
+ */
+RTDECL(char *) RTUriParsedAuthorityHost(const char *pszUri, PCRTURIPARSED pParsed);
+
+/**
+ * Extract the port number out of the authority component in a parsed URI.
+ *
+ * @returns The port number if the URI contains one, otherwise UINT32_MAX.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ */
+RTDECL(uint32_t) RTUriParsedAuthorityPort(const char *pszUri, PCRTURIPARSED pParsed);
+
+/**
+ * Extract the path out of a parsed URI.
*
* @returns the path if the URI contains one, NULL otherwise.
- * @param pszUri The URI to extract from.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
*/
-RTR3DECL(char *) RTUriPath(const char *pszUri);
+RTDECL(char *) RTUriParsedPath(const char *pszUri, PCRTURIPARSED pParsed);
/**
- * Extract the query out of an URI.
+ * Extract the query out of a parsed URI.
*
* @returns the query if the URI contains one, NULL otherwise.
- * @param pszUri The URI to extract from.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
*/
-RTR3DECL(char *) RTUriQuery(const char *pszUri);
+RTDECL(char *) RTUriParsedQuery(const char *pszUri, PCRTURIPARSED pParsed);
/**
- * Extract the fragment out of an URI.
+ * Extract the fragment out of a parsed URI.
*
* @returns the fragment if the URI contains one, NULL otherwise.
+ * @param pszUri The URI passed to RTUriParse when producing the
+ * info in @a pParsed.
+ * @param pParsed Pointer to the RTUriParse output.
+ */
+RTDECL(char *) RTUriParsedFragment(const char *pszUri, PCRTURIPARSED pParsed);
+
+
+
+/**
+ * Creates a generic URI.
+ *
+ * The returned pointer must be freed using RTStrFree().
+ *
+ * @returns the new URI on success, NULL otherwise.
+ * @param pszScheme The URI scheme.
+ * @param pszAuthority The authority part of the URI (optional).
+ * @param pszPath The path part of the URI (optional).
+ * @param pszQuery The query part of the URI (optional).
+ * @param pszFragment The fragment part of the URI (optional).
+ */
+RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
+ const char *pszFragment);
+
+/**
+ * Check whether the given scheme matches that of the URI.
+ *
+ * This does not validate the URI, it just compares the scheme, no more, no
+ * less. Thus it's much faster than using RTUriParsedScheme.
+ *
+ * @returns true if the scheme match, false if not.
+ * @param pszUri The URI to check.
+ * @param pszScheme The scheme to compare with.
+ */
+RTDECL(bool) RTUriIsSchemeMatch(const char *pszUri, const char *pszScheme);
+
+/**
+ * Extract the path out of an URI.
+ *
+ * @returns the path if the URI contains one, NULL otherwise.
* @param pszUri The URI to extract from.
+ * @deprecated
*/
-RTR3DECL(char *) RTUriFragment(const char *pszUri);
+RTDECL(char *) RTUriPath(const char *pszUri);
+
/** @defgroup grp_rt_uri_file RTUriFile - Uri file parsing and creation
- * Adds file: scheme support to the generic RTUri interface. This is partly
- * documented in http://datatracker.ietf.org/doc/rfc1738/.
+ *
+ * Implements basic "file:" scheme support to the generic RTUri interface. This
+ * is partly documented in RFC-1738.
+ *
* @ingroup grp_rt_uri
* @{
*/
-/** Auto detect in which format a path is returned. */
+/** Return the host format. */
#define URI_FILE_FORMAT_AUTO UINT32_C(0)
/** Return a path in UNIX format style. */
#define URI_FILE_FORMAT_UNIX UINT32_C(1)
@@ -121,12 +283,14 @@ RTR3DECL(char *) RTUriFragment(const char *pszUri);
/**
* Creates a file URI.
*
+ * The returned pointer must be freed using RTStrFree().
+ *
* @see RTUriCreate
*
- * @returns the new URI on success, NULL otherwise.
+ * @returns The new URI on success, NULL otherwise. Free With RTStrFree.
* @param pszPath The path of the URI.
*/
-RTR3DECL(char *) RTUriFileCreate(const char *pszPath);
+RTDECL(char *) RTUriFileCreate(const char *pszPath);
/**
* Returns the file path encoded in the URI.
@@ -135,7 +299,7 @@ RTR3DECL(char *) RTUriFileCreate(const char *pszPath);
* @param pszUri The URI to extract from.
* @param uFormat In which format should the path returned.
*/
-RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat);
+RTDECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat);
/**
* Returns the file path encoded in the URI, given a max string length.
@@ -145,7 +309,7 @@ RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat);
* @param uFormat In which format should the path returned.
* @param cbMax The max string length to inspect.
*/
-RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax);
+RTDECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax);
/** @} */
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
index c90e3e5..4f898e2 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c
@@ -252,9 +252,11 @@ int _fini(void)
RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
RTLogDestroy(RTLogSetDefaultInstance(NULL));
- mutex_destroy(&g_LdiMtx);
-
- RTR0Term();
+ if (!rc)
+ {
+ mutex_destroy(&g_LdiMtx);
+ RTR0Term();
+ }
return rc;
}
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
index 5f6894a..93f6a16 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
@@ -958,45 +958,64 @@ static int vboxserviceVMInfoWriteNetwork(void)
return RTErrConvertFromWin32(wsaErr);
}
- INTERFACE_INFO InterfaceList[20] = {0};
- unsigned long nBytesReturned = 0;
- if (WSAIoctl(sd,
- SIO_GET_INTERFACE_LIST,
- 0,
- 0,
- &InterfaceList,
- sizeof(InterfaceList),
- &nBytesReturned,
- 0,
- 0) == SOCKET_ERROR)
+ INTERFACE_INFO aInterfaces[20] = {0};
+ DWORD cbReturned = 0;
+# ifdef TARGET_NT4
+ /* Workaround for uninitialized variable used in memcpy in GetTcpipInterfaceList
+ (NT4SP1 at least). It seems to be happy enough with garbages, no failure
+ returns so far, so we just need to prevent it from crashing by filling the
+ stack with valid pointer values prior to the API call. */
+ _asm
+ {
+ mov edx, edi
+ lea eax, aInterfaces
+ mov [esp - 0x1000], eax
+ mov [esp - 0x2000], eax
+ mov ecx, 0x2000/4 - 1
+ cld
+ lea edi, [esp - 0x2000]
+ rep stosd
+ mov edi, edx
+ }
+# endif
+ if ( WSAIoctl(sd,
+ SIO_GET_INTERFACE_LIST,
+ NULL, /* pvInBuffer */
+ 0, /* cbInBuffer */
+ &aInterfaces[0], /* pvOutBuffer */
+ sizeof(aInterfaces), /* cbOutBuffer */
+ &cbReturned,
+ NULL, /* pOverlapped */
+ NULL) /* pCompletionRoutine */
+ == SOCKET_ERROR)
{
VBoxServiceError("VMInfo/Network: Failed to WSAIoctl() on socket: Error: %d\n", WSAGetLastError());
if (pAdpInfo)
RTMemFree(pAdpInfo);
return RTErrConvertFromWin32(WSAGetLastError());
}
- int cIfacesSystem = nBytesReturned / sizeof(INTERFACE_INFO);
+ int cIfacesSystem = cbReturned / sizeof(INTERFACE_INFO);
/** @todo Use GetAdaptersInfo() and GetAdapterAddresses (IPv4 + IPv6) for more information. */
for (int i = 0; i < cIfacesSystem; ++i)
{
sockaddr_in *pAddress;
u_long nFlags = 0;
- if (InterfaceList[i].iiFlags & IFF_LOOPBACK) /* Skip loopback device. */
+ if (aInterfaces[i].iiFlags & IFF_LOOPBACK) /* Skip loopback device. */
continue;
- nFlags = InterfaceList[i].iiFlags;
- pAddress = (sockaddr_in *)&(InterfaceList[i].iiAddress);
+ nFlags = aInterfaces[i].iiFlags;
+ pAddress = (sockaddr_in *)&(aInterfaces[i].iiAddress);
Assert(pAddress);
char szIp[32];
RTStrPrintf(szIp, sizeof(szIp), "%s", inet_ntoa(pAddress->sin_addr));
RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/IP", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szIp);
- pAddress = (sockaddr_in *) & (InterfaceList[i].iiBroadcastAddress);
+ pAddress = (sockaddr_in *) & (aInterfaces[i].iiBroadcastAddress);
RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Broadcast", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
- pAddress = (sockaddr_in *)&(InterfaceList[i].iiNetmask);
+ pAddress = (sockaddr_in *)&(aInterfaces[i].iiNetmask);
RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%RU32/V4/Netmask", cIfacesReport);
VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
diff --git a/src/VBox/Additions/common/crOpenGL/DD_glc.py b/src/VBox/Additions/common/crOpenGL/DD_glc.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/DD_glh.py b/src/VBox/Additions/common/crOpenGL/DD_glh.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/NULLfuncs.py b/src/VBox/Additions/common/crOpenGL/NULLfuncs.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/cr_gl.py b/src/VBox/Additions/common/crOpenGL/cr_gl.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/entrypoints.py b/src/VBox/Additions/common/crOpenGL/entrypoints.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/feedback/feedback.py b/src/VBox/Additions/common/crOpenGL/feedback/feedback.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/feedback/feedback_funcs.py b/src/VBox/Additions/common/crOpenGL/feedback/feedback_funcs.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/feedback/feedback_state.py b/src/VBox/Additions/common/crOpenGL/feedback/feedback_state.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/feedback/feedbackspu_proto.py b/src/VBox/Additions/common/crOpenGL/feedback/feedbackspu_proto.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/getprocaddress.py b/src/VBox/Additions/common/crOpenGL/getprocaddress.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/pack/pack.py b/src/VBox/Additions/common/crOpenGL/pack/pack.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_beginend.py b/src/VBox/Additions/common/crOpenGL/pack/packspu_beginend.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_flush.py b/src/VBox/Additions/common/crOpenGL/pack/packspu_flush.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/pack/packspu_proto.py b/src/VBox/Additions/common/crOpenGL/pack/packspu_proto.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/passthrough/passthrough.py b/src/VBox/Additions/common/crOpenGL/passthrough/passthrough.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/tsfuncs.py b/src/VBox/Additions/common/crOpenGL/tsfuncs.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py b/src/VBox/Additions/common/crOpenGL/windows_getprocaddress.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Additions/linux/installer/vboxadd.sh b/src/VBox/Additions/linux/installer/vboxadd.sh
index 239bf5d..e80ffc9 100755
--- a/src/VBox/Additions/linux/installer/vboxadd.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd.sh
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Linux Additions kernel module init script ($Revision: 99217 $)
+# Linux Additions kernel module init script ($Revision: 102426 $)
#
#
@@ -418,10 +418,10 @@ setup_modules()
--use-module-symvers /tmp/vboxguest-Module.symvers \
--module-source $MODULE_SRC/vboxvideo \
--no-print-directory install >> $LOG 2>&1; then
- show_error "Look at $LOG to find out what went wrong"
- return 1
+ show_error "Look at $LOG to find out what went wrong. The module is not built but the others are."
+ else
+ succ_msg
fi
- succ_msg
fi
depmod
return 0
diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c
index f1465bd..8f2077d 100644
--- a/src/VBox/Additions/linux/sharedfolders/dirops.c
+++ b/src/VBox/Additions/linux/sharedfolders/dirops.c
@@ -111,11 +111,34 @@ static int sf_dir_release(struct inode *inode, struct file *file)
}
/**
+ * Translate RTFMODE into DT_xxx (in conjunction to rtDirType())
+ * @param fMode file mode
+ * returns d_type
+ */
+static int sf_get_d_type(RTFMODE fMode)
+{
+ int d_type;
+ switch (fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FIFO: d_type = DT_FIFO; break;
+ case RTFS_TYPE_DEV_CHAR: d_type = DT_CHR; break;
+ case RTFS_TYPE_DIRECTORY: d_type = DT_DIR; break;
+ case RTFS_TYPE_DEV_BLOCK: d_type = DT_BLK; break;
+ case RTFS_TYPE_FILE: d_type = DT_REG; break;
+ case RTFS_TYPE_SYMLINK: d_type = DT_LNK; break;
+ case RTFS_TYPE_SOCKET: d_type = DT_SOCK; break;
+ case RTFS_TYPE_WHITEOUT: d_type = DT_WHT; break;
+ default: d_type = DT_UNKNOWN; break;
+ }
+ return d_type;
+}
+
+/**
* Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
*
* @returns 0 for success, 1 for end reached, Linux error code otherwise.
*/
-static int sf_getdent(struct file *dir, char d_name[NAME_MAX])
+static int sf_getdent(struct file *dir, char d_name[NAME_MAX], int *d_type)
{
loff_t cur;
struct sf_glob_info *sf_g;
@@ -201,6 +224,8 @@ static int sf_getdent(struct file *dir, char d_name[NAME_MAX])
info = (SHFLDIRINFO *) ((uintptr_t) info + size);
}
+ *d_type = sf_get_d_type(info->Info.Attr.fMode);
+
return sf_nlscpy(sf_g, d_name, NAME_MAX,
info->name.String.utf8, info->name.u16Length);
}
@@ -244,8 +269,9 @@ static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
ino_t fake_ino;
loff_t sanity;
char d_name[NAME_MAX];
+ int d_type = DT_UNKNOWN;
- err = sf_getdent(dir, d_name);
+ err = sf_getdent(dir, d_name, &d_type);
switch (err)
{
case 1:
@@ -280,13 +306,13 @@ static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
- if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, DT_UNKNOWN))
+ if (!dir_emit(ctx, d_name, strlen(d_name), fake_ino, d_type))
{
LogFunc(("dir_emit failed\n"));
return 0;
}
#else
- err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, DT_UNKNOWN);
+ err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, d_type);
if (err)
{
LogFunc(("filldir returned error %d\n", err));
diff --git a/src/VBox/Additions/linux/sharedfolders/lnkops.c b/src/VBox/Additions/linux/sharedfolders/lnkops.c
index d9f12a3..9ac005f 100644
--- a/src/VBox/Additions/linux/sharedfolders/lnkops.c
+++ b/src/VBox/Additions/linux/sharedfolders/lnkops.c
@@ -20,7 +20,11 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+static const char *sf_follow_link(struct dentry *dentry, void **cookie)
+# else
static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd)
+# endif
{
struct inode *inode = dentry->d_inode;
struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
@@ -40,22 +44,32 @@ static void *sf_follow_link(struct dentry *dentry, struct nameidata *nd)
error = -EPROTO;
}
}
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ return error ? ERR_PTR(error) : (*cookie = path);
+# else
nd_set_link(nd, error ? ERR_PTR(error) : path);
return NULL;
+# endif
}
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
static void sf_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
char *page = nd_get_link(nd);
if (!IS_ERR(page))
free_page((unsigned long)page);
}
+#endif
struct inode_operations sf_lnk_iops =
{
.readlink = generic_readlink,
.follow_link = sf_follow_link,
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ .put_link = free_page_put_link,
+# else
.put_link = sf_put_link
+# endif
};
#endif
diff --git a/src/VBox/Additions/solaris/DRM/vboxvideo_drm.c b/src/VBox/Additions/solaris/DRM/vboxvideo_drm.c
index 9ec00b8..faf563c 100644
--- a/src/VBox/Additions/solaris/DRM/vboxvideo_drm.c
+++ b/src/VBox/Additions/solaris/DRM/vboxvideo_drm.c
@@ -158,7 +158,8 @@ int _fini(void)
LogFlow((DEVICE_NAME ":_fini flow\n"));
cmn_err(CE_NOTE, DEVICE_NAME ":_fini\n");
int rc = mod_remove(&g_VBoxVideoSolarisModLinkage);
- ddi_soft_state_fini(&g_pVBoxVideoSolarisState);
+ if (!rc)
+ ddi_soft_state_fini(&g_pVBoxVideoSolarisState);
return rc;
}
diff --git a/src/VBox/Additions/solaris/Mouse/vboxms.c b/src/VBox/Additions/solaris/Mouse/vboxms.c
index 0768e8b..1aa54fc 100644
--- a/src/VBox/Additions/solaris/Mouse/vboxms.c
+++ b/src/VBox/Additions/solaris/Mouse/vboxms.c
@@ -290,7 +290,8 @@ int _fini(void)
LogRelFlow((DEVICE_NAME ":_fini\n"));
rc = mod_remove(&g_vbmsSolModLinkage);
- mutex_destroy(&g_OpenNodeState.InitMtx);
+ if (!rc)
+ mutex_destroy(&g_OpenNodeState.InitMtx);
return rc;
}
diff --git a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
index 82b6d5f..ce9114a 100644
--- a/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
+++ b/src/VBox/Additions/x11/vboxvideo/vboxvideo.c
@@ -343,7 +343,7 @@ static void setModeRandR12(ScrnInfoPtr pScrn, unsigned cScreen)
int originalX, originalY;
/* Check that this code cannot trigger the resizing bug in X.Org Server 1.3.
- * See the work-around in PreInit. */
+ * See the work-around in ScreenInit. */
xf86RandR12GetOriginalVirtualSize(pScrn, &originalX, &originalY);
VBVXASSERT(originalX == VBOX_VIDEO_MAX_VIRTUAL && originalY == VBOX_VIDEO_MAX_VIRTUAL, ("OriginalSize=%dx%d",
originalX, originalY));
@@ -938,10 +938,6 @@ VBOXPreInit(ScrnInfoPtr pScrn, int flags)
vboxAddModes(pScrn);
#ifdef VBOXVIDEO_13
- /* Work around a bug in the original X server modesetting code, which took
- * the first valid values set to these two as maxima over the server
- * lifetime. This bug was introduced on Feb 15 2007 and was fixed in commit
- * fa877d7f three months later, so it was present in X.Org Server 1.3. */
pScrn->virtualX = VBOX_VIDEO_MAX_VIRTUAL;
pScrn->virtualY = VBOX_VIDEO_MAX_VIRTUAL;
#else
@@ -1335,6 +1331,13 @@ static Bool VBOXScreenInit(ScreenPtr pScreen, int argc, char **argv)
return (FALSE);
}
+ /* Work around a bug in the original X server modesetting code, which took
+ * the first valid values set to these two as maxima over the server
+ * lifetime. This bug was introduced on Feb 15 2007 and was fixed in commit
+ * fa877d7f three months later, so it was present in X.Org Server 1.3. */
+ pScrn->virtualX = VBOX_VIDEO_MAX_VIRTUAL;
+ pScrn->virtualY = VBOX_VIDEO_MAX_VIRTUAL;
+
/* Initialise randr 1.2 mode-setting functions. */
if (!xf86CrtcScreenInit(pScreen)) {
return FALSE;
diff --git a/src/VBox/Debugger/DBGCTcp.cpp b/src/VBox/Debugger/DBGCTcp.cpp
index 6e18e40..0d5ef3d 100644
--- a/src/VBox/Debugger/DBGCTcp.cpp
+++ b/src/VBox/Debugger/DBGCTcp.cpp
@@ -101,6 +101,8 @@ static DECLCALLBACK(int) dbgcTcpBackRead(PDBGCBACK pBack, void *pvBuf, size_t cb
if (!pDbgcTcp->fAlive)
return VERR_INVALID_HANDLE;
int rc = RTTcpRead(pDbgcTcp->Sock, pvBuf, cbBuf, pcbRead);
+ if (RT_SUCCESS(rc) && pcbRead != NULL && *pcbRead == 0)
+ rc = VERR_NET_SHUTDOWN;
if (RT_FAILURE(rc))
pDbgcTcp->fAlive = false;
return rc;
@@ -135,7 +137,7 @@ static DECLCALLBACK(int) dbgcTcpBackWrite(PDBGCBACK pBack, const void *pvBuf, si
/* write newlines */
if (*(const char *)pvBuf == '\n')
{
- rc = RTTcpWrite(pDbgcTcp->Sock, "\n\r", 2);
+ rc = RTTcpWrite(pDbgcTcp->Sock, "\r\n", 2);
cb = 1;
}
/* write till next newline */
diff --git a/src/VBox/Debugger/DBGConsole.cpp b/src/VBox/Debugger/DBGConsole.cpp
index 0784855..9d63fdb 100644
--- a/src/VBox/Debugger/DBGConsole.cpp
+++ b/src/VBox/Debugger/DBGConsole.cpp
@@ -563,9 +563,15 @@ int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
&& pDbgc->fReady)
pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
}
- else
- /* Received nonsense; just skip it. */
- pDbgc->iRead = pDbgc->iWrite;
+ /*
+ * else - we have incomplete line, so leave it in the buffer and
+ * wait for more input.
+ *
+ * Windows telnet client is in "character at a time" mode by
+ * default and putty sends eol as a separate packet that will be
+ * most likely read separately from the command line it
+ * terminates.
+ */
return rc;
}
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/BPDG/StringTable.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/BPDG/StringTable.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/FdfParserLite.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/FdfParserLite.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Identification.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Identification.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/CommonDataClass/CommonClass.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/CommonDataClass/CommonClass.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/CommonDataClass/FdfClass.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/CommonDataClass/FdfClass.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/CodeFragment.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/CodeFragment.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/ParserWarning.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/ParserWarning.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/Xml/XmlRoutines.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/Xml/XmlRoutines.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/Xml/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Ecc/Xml/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/CodeFragment.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/CodeFragment.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/ParserWarning.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/ParserWarning.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/Report.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Eot/Report.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/GenFds/Attribute.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/GenFds/Attribute.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Table/Table.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Table/Table.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/BuildVersion.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/BuildVersion.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Core/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/GenMetaFile/GenXmlFile.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/GenMetaFile/GenXmlFile.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/GenMetaFile/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/GenMetaFile/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/DataType.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/DataType.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/GlobalData.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/GlobalData.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/Xml/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/Xml/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Library/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Logger/StringTable.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Logger/StringTable.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Logger/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Logger/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/POM/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/POM/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/InfCommonObject.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/InfCommonObject.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/InfHeaderObject.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/InfHeaderObject.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/Parser/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Object/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Parser/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/PomAdapter/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/PomAdapter/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Xml/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/UPT/Xml/__init__.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/ResetVector/Vtf0/Build.py b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/ResetVector/Vtf0/Build.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/ResetVector/Vtf0/Tools/FixupForRawSection.py b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/ResetVector/Vtf0/Tools/FixupForRawSection.py
old mode 100644
new mode 100755
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd
index 7b08f17..ac4d3af 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd differ
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd
index c3bd71e..26617b4 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd differ
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.asm
index 1e7a6ce..fea6b58 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.asm
@@ -6779,7 +6779,7 @@ vesa_pm_end: ; 0xc4714 LB 0x1
section _DATA progbits vstart=0x4800 align=1 ; size=0x36e1 class=DATA group=DGROUP
_msg_vga_init: ; 0xc4800 LB 0x2f
- db 'Oracle VM VirtualBox Version 4.3.30 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 4.3.32 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc482f LB 0x80
db 000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
db 002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
@@ -7667,7 +7667,7 @@ _vbebios_vendor_name: ; 0xc7e35 LB 0x13
_vbebios_product_name: ; 0xc7e48 LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7e69 LB 0x24
- db 'Oracle VM VirtualBox Version 4.3.30', 000h
+ db 'Oracle VM VirtualBox Version 4.3.32', 000h
_vbebios_info_string: ; 0xc7e8d LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7eb8 LB 0x29
@@ -7698,4 +7698,4 @@ section CONST2 progbits vstart=0x7ee2 align=1 ; size=0x0 class=DATA group=DGROUP
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
- db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 060h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 05ch
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.md5sum
index 4e1525a..b5abc0d 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative.md5sum
@@ -1 +1 @@
-09b3c82e35301f4c7fc988c6b6ebd32b *VBoxVgaBios.rom
+c7a975f86cc75eff05957f7d423d50ee *VBoxVgaBios.rom
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
index 6c4aff6..17823dd 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA.cpp
@@ -23,9 +23,9 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
#define VMSVGA_USE_EMT_HALT_CODE
#include <VBox/vmm/pdmdev.h>
@@ -44,6 +44,7 @@
#include <iprt/semaphore.h>
#include <iprt/uuid.h>
#ifdef IN_RING3
+# include <iprt/ctype.h>
# include <iprt/mem.h>
#endif
@@ -75,9 +76,9 @@
#endif
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
/**
* Macro for checking if a fixed FIFO register is valid according to the
* current FIFO configuration.
@@ -89,17 +90,21 @@
#define VMSVGA_IS_VALID_FIFO_REG(a_iIndex, a_offFifoMin) ( ((a_iIndex) + 1) * sizeof(uint32_t) <= (a_offFifoMin) )
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-/* 64-bit GMR descriptor */
-typedef struct
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * 64-bit GMR descriptor.
+ */
+typedef struct
{
RTGCPHYS GCPhys;
uint64_t numPages;
} VMSVGAGMRDESCRIPTOR, *PVMSVGAGMRDESCRIPTOR;
-/* GMR slot */
+/**
+ * GMR slot
+ */
typedef struct
{
uint32_t cMaxPages;
@@ -108,8 +113,11 @@ typedef struct
PVMSVGAGMRDESCRIPTOR paDesc;
} GMR, *PGMR;
-/* Internal SVGA state. */
-typedef struct
+#ifdef IN_RING3
+/**
+ * Internal SVGA ring-3 only state.
+ */
+typedef struct VMSVGAR3STATE
{
GMR aGMR[VMSVGA_MAX_GMR_IDS];
struct
@@ -118,7 +126,7 @@ typedef struct
uint32_t bytesPerLine;
SVGAGMRImageFormat format;
} GMRFB;
- struct
+ struct
{
bool fActive;
uint32_t xHotspot;
@@ -130,18 +138,18 @@ typedef struct
} Cursor;
SVGAColorBGRX colorAnnotation;
-#ifdef VMSVGA_USE_EMT_HALT_CODE
+# ifdef VMSVGA_USE_EMT_HALT_CODE
/** Number of EMTs in BusyDelayedEmts (quicker than scanning the set). */
uint32_t volatile cBusyDelayedEmts;
/** Set of EMTs that are */
VMCPUSET BusyDelayedEmts;
-#else
+# else
/** Number of EMTs waiting on hBusyDelayedEmts. */
uint32_t volatile cBusyDelayedEmts;
/** Semaphore that EMTs wait on when reading SVGA_REG_BUSY and the FIFO is
* busy (ugly). */
RTSEMEVENTMULTI hBusyDelayedEmts;
-#endif
+# endif
/** Tracks how much time we waste reading SVGA_REG_BUSY with a busy FIFO. */
STAMPROFILE StatBusyDelayEmts;
@@ -156,7 +164,8 @@ typedef struct
STAMCOUNTER StatFifoTodoWoken;
STAMPROFILE StatFifoStalls;
-} VMSVGASTATE, *PVMSVGASTATE;
+} VMSVGAR3STATE, *PVMSVGAR3STATE;
+#endif /* IN_RING3 */
#ifdef IN_RING3
@@ -183,36 +192,36 @@ static SSMFIELD const g_aGMRFields[] =
};
/**
- * SSM descriptor table for the VMSVGASTATE structure.
+ * SSM descriptor table for the VMSVGAR3STATE structure.
*/
-static SSMFIELD const g_aVMSVGASTATEFields[] =
+static SSMFIELD const g_aVMSVGAR3STATEFields[] =
{
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, aGMR),
- SSMFIELD_ENTRY( VMSVGASTATE, GMRFB),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.fActive),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.xHotspot),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.yHotspot),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.width),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.height),
- SSMFIELD_ENTRY( VMSVGASTATE, Cursor.cbData),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGASTATE, Cursor.pData),
- SSMFIELD_ENTRY( VMSVGASTATE, colorAnnotation),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, cBusyDelayedEmts),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, aGMR),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, GMRFB),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.fActive),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.xHotspot),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.yHotspot),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.width),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.height),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, Cursor.cbData),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAR3STATE, Cursor.pData),
+ SSMFIELD_ENTRY( VMSVGAR3STATE, colorAnnotation),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, cBusyDelayedEmts),
#ifdef VMSVGA_USE_EMT_HALT_CODE
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, BusyDelayedEmts),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, BusyDelayedEmts),
#else
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, hBusyDelayedEmts),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, hBusyDelayedEmts),
#endif
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatBusyDelayEmts),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatR3CmdPresent),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatR3CmdDrawPrimitive),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatR3CmdSurfaceDMA),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoCommands),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoErrors),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoUnkCmds),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoTodoTimeout),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoTodoWoken),
- SSMFIELD_ENTRY_IGNORE( VMSVGASTATE, StatFifoStalls),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatBusyDelayEmts),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdPresent),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdDrawPrimitive),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatR3CmdSurfaceDMA),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoCommands),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoErrors),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoUnkCmds),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoTodoTimeout),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoTodoWoken),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAR3STATE, StatFifoStalls),
SSMFIELD_ENTRY_TERM()
};
@@ -224,10 +233,10 @@ static SSMFIELD const g_aVGAStateSVGAFields[] =
SSMFIELD_ENTRY_IGNORE( VMSVGAState, u64HostWindowId),
SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pFIFOR3),
SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pFIFOR0),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pSVGAState),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pSvgaR3State),
SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, p3dState),
SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pFrameBufferBackup),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pFIFOExtCmdParam),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGAState, pvFIFOExtCmdParam),
SSMFIELD_ENTRY_IGN_GCPHYS( VMSVGAState, GCPhysFIFO),
SSMFIELD_ENTRY_IGNORE( VMSVGAState, cbFIFO),
SSMFIELD_ENTRY( VMSVGAState, u32SVGAId),
@@ -259,6 +268,7 @@ static SSMFIELD const g_aVGAStateSVGAFields[] =
SSMFIELD_ENTRY( VMSVGAState, f3DEnabled),
SSMFIELD_ENTRY( VMSVGAState, fVRAMTracking),
SSMFIELD_ENTRY_IGNORE( VMSVGAState, u8FIFOExtCommand),
+ SSMFIELD_ENTRY_IGNORE( VMSVGAState, fFifoExtCommandWakeup),
SSMFIELD_ENTRY_TERM()
};
@@ -508,30 +518,53 @@ static const char *vmsvgaFIFOCmdToString(uint32_t u32Cmd)
}
#endif
+#ifdef IN_RING3
/**
- * Inform the VGA device of viewport changes (as a result of e.g. scrolling)
- *
- * @param pInterface Pointer to this interface.
- * @param
- * @param uScreenId The screen updates are for.
- * @param x The upper left corner x coordinate of the new viewport rectangle
- * @param y The upper left corner y coordinate of the new viewport rectangle
- * @param cx The width of the new viewport rectangle
- * @param cy The height of the new viewport rectangle
- * @thread The emulation thread.
+ * @interface_method_impl{PDMIDISPLAYPORT::pfnSetViewport}
*/
-DECLCALLBACK(void) vmsvgaPortSetViewPort(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
+DECLCALLBACK(void) vmsvgaPortSetViewport(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
{
PVGASTATE pThis = RT_FROM_MEMBER(pInterface, VGASTATE, IPort);
Log(("vmsvgaPortSetViewPort: screen %d (%d,%d)(%d,%d)\n", uScreenId, x, y, cx, cy));
+ VMSVGAVIEWPORT const OldViewport = pThis->svga.viewport;
+
+ if (x < pThis->svga.uWidth)
+ {
+ pThis->svga.viewport.x = x;
+ pThis->svga.viewport.cx = RT_MIN(cx, pThis->svga.uWidth - x);
+ pThis->svga.viewport.xRight = x + pThis->svga.viewport.cx;
+ }
+ else
+ {
+ pThis->svga.viewport.x = pThis->svga.uWidth;
+ pThis->svga.viewport.cx = 0;
+ pThis->svga.viewport.xRight = pThis->svga.uWidth;
+ }
+ if (y < pThis->svga.uHeight)
+ {
+ pThis->svga.viewport.y = y;
+ pThis->svga.viewport.cy = RT_MIN(cy, pThis->svga.uHeight - y);
+ pThis->svga.viewport.yLowWC = pThis->svga.uHeight - y - pThis->svga.viewport.cy;
+ pThis->svga.viewport.yHighWC = pThis->svga.uHeight - y;
+ }
+ else
+ {
+ pThis->svga.viewport.y = pThis->svga.uHeight;
+ pThis->svga.viewport.cy = 0;
+ pThis->svga.viewport.yLowWC = 0;
+ pThis->svga.viewport.yHighWC = 0;
+ }
- pThis->svga.viewport.x = x;
- pThis->svga.viewport.y = y;
- pThis->svga.viewport.cx = RT_MIN(cx, (uint32_t)pThis->svga.uWidth);
- pThis->svga.viewport.cy = RT_MIN(cy, (uint32_t)pThis->svga.uHeight);
- return;
+# ifdef VBOX_WITH_VMSVGA3D
+ /*
+ * Now inform the 3D backend.
+ */
+ if (pThis->svga.f3DEnabled)
+ vmsvga3dUpdateHostScreenViewport(pThis, uScreenId, &OldViewport);
+# endif
}
+#endif /* IN_RING3 */
/**
* Read port register
@@ -802,7 +835,7 @@ PDMBOTHCBDECL(int) vmsvgaReadPort(PVGASTATE pThis, uint32_t *pu32)
#elif defined(VMSVGA_USE_EMT_HALT_CODE)
/* The guest is basically doing a HLT via the device here, but with
a special wake up condition on FIFO completion. */
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
STAM_REL_PROFILE_START(&pSVGAState->StatBusyDelayEmts, EmtDelay);
PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
VMCPUID idCpu = PDMDevHlpGetVMCPU(pThis->pDevInsR3)->idCpu; /** @todo add a separate dev helper for this. */
@@ -817,7 +850,7 @@ PDMBOTHCBDECL(int) vmsvgaReadPort(PVGASTATE pThis, uint32_t *pu32)
/* Delay the EMT a bit so the FIFO and others can get some work done.
This used to be a crude 50 ms sleep. The current code tries to be
more efficient, but the consept is still very crude. */
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
STAM_REL_PROFILE_START(&pSVGAState->StatBusyDelayEmts, EmtDelay);
RTThreadYield();
if (pThis->svga.fBusy)
@@ -972,7 +1005,7 @@ int vmsvgaChangeMode(PVGASTATE pThis)
|| pThis->svga.uHeight == 0
|| pThis->svga.uBpp == 0)
{
- /* Invalid mode change. */
+ /* Invalid mode change - BB does this early in the boot up. */
Log(("vmsvgaChangeMode: BOGUS sEnable LFB mode and resize to (%d,%d) bpp=%d\n", pThis->svga.uWidth, pThis->svga.uHeight, pThis->svga.uBpp));
return VINF_SUCCESS;
}
@@ -1003,15 +1036,18 @@ int vmsvgaChangeMode(PVGASTATE pThis)
pThis->last_scr_height = pThis->svga.uHeight;
pThis->last_width = pThis->svga.uWidth;
pThis->last_height = pThis->svga.uHeight;
-
+
ASMAtomicOrU32(&pThis->svga.u32ActionFlags, VMSVGA_ACTION_CHANGEMODE);
/* vmsvgaPortSetViewPort not called after state load; set sensible defaults. */
if ( pThis->svga.viewport.cx == 0
&& pThis->svga.viewport.cy == 0)
{
- pThis->svga.viewport.cx = pThis->svga.uWidth;
- pThis->svga.viewport.cy = pThis->svga.uHeight;
+ pThis->svga.viewport.cx = pThis->svga.uWidth;
+ pThis->svga.viewport.xRight = pThis->svga.uWidth;
+ pThis->svga.viewport.cy = pThis->svga.uHeight;
+ pThis->svga.viewport.yHighWC = pThis->svga.uHeight;
+ pThis->svga.viewport.yLowWC = 0;
}
return VINF_SUCCESS;
}
@@ -1051,14 +1087,16 @@ DECLINLINE(void) vmsvgaSafeFifoBusyRegUpdate(PVGASTATE pThis, bool fState)
*/
PDMBOTHCBDECL(int) vmsvgaWritePort(PVGASTATE pThis, uint32_t u32)
{
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
- int rc = VINF_SUCCESS;
+#ifdef IN_RING3
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
+#endif
+ int rc = VINF_SUCCESS;
Log(("vmsvgaWritePort index=%s (%d) val=%#x\n", vmsvgaIndexToString(pThis), pThis->svga.u32IndexReg, u32));
switch (pThis->svga.u32IndexReg)
{
case SVGA_REG_ID:
- if ( u32 == SVGA_ID_0
+ if ( u32 == SVGA_ID_0
|| u32 == SVGA_ID_1
|| u32 == SVGA_ID_2)
pThis->svga.u32SVGAId = u32;
@@ -1076,7 +1114,7 @@ PDMBOTHCBDECL(int) vmsvgaWritePort(PVGASTATE pThis, uint32_t u32)
break;
#ifdef IN_RING3
- if ( u32 == 1
+ if ( u32 == 1
&& pThis->svga.fEnabled == false)
{
/* Make a backup copy of the first 32k in order to save font data etc. */
@@ -1360,7 +1398,7 @@ PDMBOTHCBDECL(int) vmsvgaWritePort(PVGASTATE pThis, uint32_t u32)
if (pThis->svga.fTraces == u32)
break; /* nothing to do */
-#ifdef IN_RING3
+#ifdef IN_RING3
vmsvgaSetTraces(pThis, !!u32);
#else
rc = VINF_IOM_R3_IOPORT_WRITE;
@@ -1523,7 +1561,7 @@ PDMBOTHCBDECL(int) vmsvgaIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port
* @param fWriteAccess Read or write access
*/
static int vmsvgaFIFOAccess(PVM pVM, PVGASTATE pThis, RTGCPHYS GCPhys, bool fWriteAccess)
-{
+{
RTGCPHYS GCPhysOffset = GCPhys - pThis->svga.GCPhysFIFO;
uint32_t *pFIFO = pThis->svga.pFIFOR3;
@@ -1901,7 +1939,7 @@ static DECLCALLBACK(int) vmsvgaR3GMRAccessHandler(PVM pVM, RTGCPHYS GCPhys, void
{
PVGASTATE pThis = (PVGASTATE)pvUser;
Assert(pThis);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
NOREF(pvPhys); NOREF(pvBuf); NOREF(cbBuf);
Log(("vmsvgaR3GMRAccessHandler: GMR access to page %RGp\n", GCPhys));
@@ -1914,7 +1952,7 @@ static DECLCALLBACK(int) vmsvgaR3GMRAccessHandler(PVM pVM, RTGCPHYS GCPhys, void
{
for (uint32_t j = 0; j < pGMR->numDescriptors; j++)
{
- if ( GCPhys >= pGMR->paDesc[j].GCPhys
+ if ( GCPhys >= pGMR->paDesc[j].GCPhys
&& GCPhys < pGMR->paDesc[j].GCPhys + pGMR->paDesc[j].numPages * PAGE_SIZE)
{
/*
@@ -1936,8 +1974,8 @@ end:
/* Callback handler for VMR3ReqCallWait */
static DECLCALLBACK(int) vmsvgaRegisterGMR(PPDMDEVINS pDevIns, uint32_t gmrId)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
PGMR pGMR = &pSVGAState->aGMR[gmrId];
int rc;
@@ -1958,8 +1996,8 @@ static DECLCALLBACK(int) vmsvgaRegisterGMR(PPDMDEVINS pDevIns, uint32_t gmrId)
/* Callback handler for VMR3ReqCallWait */
static DECLCALLBACK(int) vmsvgaUnregisterGMR(PPDMDEVINS pDevIns, uint32_t gmrId)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
PGMR pGMR = &pSVGAState->aGMR[gmrId];
for (uint32_t i = 0; i < pGMR->numDescriptors; i++)
@@ -1973,7 +2011,7 @@ static DECLCALLBACK(int) vmsvgaUnregisterGMR(PPDMDEVINS pDevIns, uint32_t gmrId)
/* Callback handler for VMR3ReqCallWait */
static DECLCALLBACK(int) vmsvgaResetGMRHandlers(PVGASTATE pThis)
{
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
for (uint32_t i = 0; i < RT_ELEMENTS(pSVGAState->aGMR); i++)
{
@@ -1988,7 +2026,7 @@ static DECLCALLBACK(int) vmsvgaResetGMRHandlers(PVGASTATE pThis)
}
}
}
- return VINF_SUCCESS;
+ return VINF_SUCCESS;
}
# endif /* IN_RING3 */
@@ -1999,13 +2037,190 @@ static DECLCALLBACK(int) vmsvgaResetGMRHandlers(PVGASTATE pThis)
#ifdef IN_RING3
/**
+ * Worker for vmsvgaR3FifoThread that handles an external command.
+ *
+ * @param pThis VGA device instance data.
+ */
+static void vmsvgaR3FifoHandleExtCmd(PVGASTATE pThis)
+{
+ uint8_t uExtCmd = pThis->svga.u8FIFOExtCommand;
+ switch (pThis->svga.u8FIFOExtCommand)
+ {
+ case VMSVGA_FIFO_EXTCMD_RESET:
+ Log(("vmsvgaFIFOLoop: reset the fifo thread.\n"));
+ Assert(pThis->svga.pvFIFOExtCmdParam == NULL);
+# ifdef VBOX_WITH_VMSVGA3D
+ if (pThis->svga.f3DEnabled)
+ {
+ /* The 3d subsystem must be reset from the fifo thread. */
+ vmsvga3dReset(pThis);
+ }
+# endif
+ break;
+
+ case VMSVGA_FIFO_EXTCMD_TERMINATE:
+ Log(("vmsvgaFIFOLoop: terminate the fifo thread.\n"));
+ Assert(pThis->svga.pvFIFOExtCmdParam == NULL);
+# ifdef VBOX_WITH_VMSVGA3D
+ if (pThis->svga.f3DEnabled)
+ {
+ /* The 3d subsystem must be shut down from the fifo thread. */
+ vmsvga3dTerminate(pThis);
+ }
+# endif
+ break;
+
+ case VMSVGA_FIFO_EXTCMD_SAVESTATE:
+ {
+ Log(("vmsvgaFIFOLoop: VMSVGA_FIFO_EXTCMD_SAVESTATE.\n"));
+# ifdef VBOX_WITH_VMSVGA3D
+ PSSMHANDLE pSSM = (PSSMHANDLE)pThis->svga.pvFIFOExtCmdParam;
+ AssertLogRelMsgBreak(RT_VALID_PTR(pSSM), ("pSSM=%p\n", pSSM));
+ vmsvga3dSaveExec(pThis, pSSM);
+# endif
+ break;
+ }
+
+ case VMSVGA_FIFO_EXTCMD_LOADSTATE:
+ {
+ Log(("vmsvgaFIFOLoop: VMSVGA_FIFO_EXTCMD_LOADSTATE.\n"));
+# ifdef VBOX_WITH_VMSVGA3D
+ PVMSVGA_STATE_LOAD pLoadState = (PVMSVGA_STATE_LOAD)pThis->svga.pvFIFOExtCmdParam;
+ AssertLogRelMsgBreak(RT_VALID_PTR(pLoadState), ("pLoadState=%p\n", pLoadState));
+ vmsvga3dLoadExec(pThis, pLoadState->pSSM, pLoadState->uVersion, pLoadState->uPass);
+# endif
+ break;
+ }
+
+ case VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS:
+ {
+# ifdef VBOX_WITH_VMSVGA3D
+ uint32_t sid = (uint32_t)(uintptr_t)pThis->svga.pvFIFOExtCmdParam;
+ Log(("vmsvgaFIFOLoop: VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS sid=%#x\n", sid));
+ vmsvga3dUpdateHeapBuffersForSurfaces(pThis, sid);
+# endif
+ break;
+ }
+
+
+ default:
+ AssertLogRelMsgFailed(("uExtCmd=%#x pvFIFOExtCmdParam=%p\n", uExtCmd, pThis->svga.pvFIFOExtCmdParam));
+ break;
+ }
+
+ /*
+ * Signal the end of the external command.
+ */
+ pThis->svga.pvFIFOExtCmdParam = NULL;
+ pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_NONE;
+ ASMMemoryFence(); /* paranoia^2 */
+ int rc = RTSemEventSignal(pThis->svga.FIFOExtCmdSem);
+ AssertLogRelRC(rc);
+}
+
+/**
+ * Worker for vmsvgaR3Destruct, vmsvgaR3Reset, vmsvgaR3Save and vmsvgaR3Load for
+ * doing a job on the FIFO thread (even when it's officially suspended).
+ *
+ * @returns VBox status code (fully asserted).
+ * @param pThis VGA device instance data.
+ * @param uExtCmd The command to execute on the FIFO thread.
+ * @param pvParam Pointer to command parameters.
+ * @param cMsWait The time to wait for the command, given in
+ * milliseconds.
+ */
+static int vmsvgaR3RunExtCmdOnFifoThread(PVGASTATE pThis, uint8_t uExtCmd, void *pvParam, RTMSINTERVAL cMsWait)
+{
+ Assert(cMsWait >= RT_MS_1SEC * 5);
+ AssertLogRelMsg(pThis->svga.u8FIFOExtCommand == VMSVGA_FIFO_EXTCMD_NONE,
+ ("old=%d new=%d\n", pThis->svga.u8FIFOExtCommand, uExtCmd));
+
+ int rc;
+ PPDMTHREAD pThread = pThis->svga.pFIFOIOThread;
+ PDMTHREADSTATE enmState = pThread->enmState;
+ if (enmState == PDMTHREADSTATE_SUSPENDED)
+ {
+ /*
+ * The thread is suspended, we have to temporarily wake it up so it can
+ * perform the task.
+ * (We ASSUME not racing code here, both wrt thread state and ext commands.)
+ */
+ Log(("vmsvgaR3RunExtCmdOnFifoThread: uExtCmd=%d enmState=SUSPENDED\n", uExtCmd));
+ /* Post the request. */
+ pThis->svga.fFifoExtCommandWakeup = true;
+ pThis->svga.pvFIFOExtCmdParam = pvParam;
+ pThis->svga.u8FIFOExtCommand = uExtCmd;
+ ASMMemoryFence(); /* paranoia^3 */
+
+ /* Resume the thread. */
+ rc = PDMR3ThreadResume(pThread);
+ AssertLogRelRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ /* Wait. Take care in case the semaphore was already posted (same as below). */
+ rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, cMsWait);
+ if ( rc == VINF_SUCCESS
+ && pThis->svga.u8FIFOExtCommand == uExtCmd)
+ rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, cMsWait);
+ AssertLogRelMsg(pThis->svga.u8FIFOExtCommand != uExtCmd || RT_FAILURE_NP(rc),
+ ("%#x %Rrc\n", pThis->svga.u8FIFOExtCommand, rc));
+
+ /* suspend the thread */
+ pThis->svga.fFifoExtCommandWakeup = false;
+ int rc2 = PDMR3ThreadSuspend(pThread);
+ AssertLogRelRC(rc2);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ pThis->svga.fFifoExtCommandWakeup = false;
+ pThis->svga.pvFIFOExtCmdParam = NULL;
+ }
+ else if (enmState == PDMTHREADSTATE_RUNNING)
+ {
+ /*
+ * The thread is running, should only happen during reset and vmsvga3dsfc.
+ * We ASSUME not racing code here, both wrt thread state and ext commands.
+ */
+ Log(("vmsvgaR3RunExtCmdOnFifoThread: uExtCmd=%d enmState=RUNNING\n", uExtCmd));
+ Assert(uExtCmd == VMSVGA_FIFO_EXTCMD_RESET || uExtCmd == VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS);
+
+ /* Post the request. */
+ pThis->svga.pvFIFOExtCmdParam = pvParam;
+ pThis->svga.u8FIFOExtCommand = uExtCmd;
+ ASMMemoryFence(); /* paranoia^2 */
+ rc = SUPSemEventSignal(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem);
+ AssertLogRelRC(rc);
+
+ /* Wait. Take care in case the semaphore was already posted (same as above). */
+ rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, cMsWait);
+ if ( rc == VINF_SUCCESS
+ && pThis->svga.u8FIFOExtCommand == uExtCmd)
+ rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, cMsWait); /* it was already posted, retry the wait. */
+ AssertLogRelMsg(pThis->svga.u8FIFOExtCommand != uExtCmd || RT_FAILURE_NP(rc),
+ ("%#x %Rrc\n", pThis->svga.u8FIFOExtCommand, rc));
+
+ pThis->svga.pvFIFOExtCmdParam = NULL;
+ }
+ else
+ {
+ /*
+ * Something is wrong with the thread!
+ */
+ AssertLogRelMsgFailed(("uExtCmd=%d enmState=%d\n", uExtCmd, enmState));
+ rc = VERR_INVALID_STATE;
+ }
+ return rc;
+}
+
+
+/**
* Marks the FIFO non-busy, notifying any waiting EMTs.
*
* @param pThis The VGA state.
* @param pSVGAState Pointer to the ring-3 only SVGA state data.
* @param offFifoMin The start byte offset of the command FIFO.
*/
-static void vmsvgaFifoSetNotBusy(PVGASTATE pThis, PVMSVGASTATE pSVGAState, uint32_t offFifoMin)
+static void vmsvgaFifoSetNotBusy(PVGASTATE pThis, PVMSVGAR3STATE pSVGAState, uint32_t offFifoMin)
{
ASMAtomicAndU32(&pThis->svga.fBusy, ~VMSVGA_BUSY_F_FIFO);
if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_BUSY, offFifoMin))
@@ -2055,7 +2270,7 @@ static void vmsvgaFifoSetNotBusy(PVGASTATE pThis, PVMSVGASTATE pSVGAState, uint3
static void *vmsvgaFIFOGetCmdPayload(uint32_t cbPayloadReq, uint32_t volatile *pFIFO,
uint32_t offCurrentCmd, uint32_t offFifoMin, uint32_t offFifoMax,
uint8_t *pbBounceBuf, uint32_t *pcbAlreadyRead,
- PPDMTHREAD pThread, PVGASTATE pThis, PVMSVGASTATE pSVGAState)
+ PPDMTHREAD pThread, PVGASTATE pThis, PVMSVGAR3STATE pSVGAState)
{
Assert(pbBounceBuf);
Assert(pcbAlreadyRead);
@@ -2187,14 +2402,31 @@ static void *vmsvgaFIFOGetCmdPayload(uint32_t cbPayloadReq, uint32_t volatile *p
/* The async FIFO handling thread. */
static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
{
- PVGASTATE pThis = (PVGASTATE)pThread->pvUser;
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
- int rc;
+ PVGASTATE pThis = (PVGASTATE)pThread->pvUser;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
+ int rc;
if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
return VINF_SUCCESS;
/*
+ * Special mode where we only execute an external command and the go back
+ * to being suspended. Currently, all ext cmds ends up here, with the reset
+ * one also being eligble for runtime execution further down as well.
+ */
+ if (pThis->svga.fFifoExtCommandWakeup)
+ {
+ vmsvgaR3FifoHandleExtCmd(pThis);
+ while (pThread->enmState == PDMTHREADSTATE_RUNNING)
+ if (pThis->svga.u8FIFOExtCommand == VMSVGA_FIFO_EXTCMD_NONE)
+ SUPSemEventWaitNoResume(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem, RT_MS_1MIN);
+ else
+ vmsvgaR3FifoHandleExtCmd(pThis);
+ return VINF_SUCCESS;
+ }
+
+
+ /*
* Signal the semaphore to make sure we don't wait for 250 after a
* suspend & resume scenario (see vmsvgaFIFOGetCmdPayload).
*/
@@ -2245,64 +2477,22 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
Log(("vmsvgaFIFOLoop: next %x stop %x\n", pFIFO[SVGA_FIFO_NEXT_CMD], pFIFO[SVGA_FIFO_STOP]));
/*
- * Handle external commands.
+ * Handle external commands (currently only reset).
*/
if (pThis->svga.u8FIFOExtCommand != VMSVGA_FIFO_EXTCMD_NONE)
{
- switch (pThis->svga.u8FIFOExtCommand)
- {
- case VMSVGA_FIFO_EXTCMD_RESET:
- Log(("vmsvgaFIFOLoop: reset the fifo thread.\n"));
-# ifdef VBOX_WITH_VMSVGA3D
- if (pThis->svga.f3DEnabled)
- {
- /* The 3d subsystem must be reset from the fifo thread. */
- vmsvga3dReset(pThis);
- }
-# endif
- break;
-
- case VMSVGA_FIFO_EXTCMD_TERMINATE:
- Log(("vmsvgaFIFOLoop: terminate the fifo thread.\n"));
-# ifdef VBOX_WITH_VMSVGA3D
- if (pThis->svga.f3DEnabled)
- {
- /* The 3d subsystem must be shut down from the fifo thread. */
- vmsvga3dTerminate(pThis);
- }
-# endif
- break;
-
- case VMSVGA_FIFO_EXTCMD_SAVESTATE:
- Log(("vmsvgaFIFOLoop: VMSVGA_FIFO_EXTCMD_SAVESTATE.\n"));
-# ifdef VBOX_WITH_VMSVGA3D
- vmsvga3dSaveExec(pThis, (PSSMHANDLE)pThis->svga.pFIFOExtCmdParam);
-# endif
- break;
-
- case VMSVGA_FIFO_EXTCMD_LOADSTATE:
- {
- Log(("vmsvgaFIFOLoop: VMSVGA_FIFO_EXTCMD_LOADSTATE.\n"));
-# ifdef VBOX_WITH_VMSVGA3D
- PVMSVGA_STATE_LOAD pLoadState = (PVMSVGA_STATE_LOAD)pThis->svga.pFIFOExtCmdParam;
- vmsvga3dLoadExec(pThis, pLoadState->pSSM, pLoadState->uVersion, pLoadState->uPass);
-# endif
- break;
- }
- }
-
- pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_NONE;
-
- /* Signal the end of the external command. */
- RTSemEventSignal(pThis->svga.FIFOExtCmdSem);
+ vmsvgaR3FifoHandleExtCmd(pThis);
continue;
}
- if ( !pThis->svga.fEnabled
- || !pThis->svga.fConfigured)
+ /*
+ * The device must be enabled and configured.
+ */
+ if ( !pThis->svga.fEnabled
+ || !pThis->svga.fConfigured)
{
vmsvgaFifoSetNotBusy(pThis, pSVGAState, pFIFO[SVGA_FIFO_MIN]);
- continue; /* device not enabled. */
+ continue;
}
/*
@@ -2373,7 +2563,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
* Quit if pending external command or changes in the thread state.
*/
bool fDone = false;
- while ( !(fDone = pFIFO[SVGA_FIFO_NEXT_CMD] == offCurrentCmd)
+ while ( !(fDone = (pFIFO[SVGA_FIFO_NEXT_CMD] == offCurrentCmd))
&& pThread->enmState == PDMTHREADSTATE_RUNNING)
{
uint32_t cbPayload = 0;
@@ -2389,7 +2579,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
# else
{/*nothing*/}
# endif
- /* Check for pending external commands. */
+ /* Check for pending external commands (reset). */
if (pThis->svga.u8FIFOExtCommand != VMSVGA_FIFO_EXTCMD_NONE)
break;
@@ -2406,7 +2596,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
break;
case SVGA_CMD_FENCE:
- {
+ {
SVGAFifoCmdFence *pCmdFence;
VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmdFence, SVGAFifoCmdFence, sizeof(*pCmdFence));
if (VMSVGA_IS_VALID_FIFO_REG(SVGA_FIFO_FENCE, offFifoMin))
@@ -2826,7 +3016,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
VMSVGAFIFO_GET_CMD_BUFFER_BREAK(pCmd, SVGAFifoCmdAnnotationFill, sizeof(*pCmd));
Log(("vmsvgaFIFOLoop: SVGA_CMD_ANNOTATION_FILL red=%x green=%x blue=%x\n", pCmd->color.s.r, pCmd->color.s.g, pCmd->color.s.b));
- pSVGAState->colorAnnotation = pCmd->color;
+ pSVGAState->colorAnnotation = pCmd->color;
break;
}
@@ -2869,7 +3059,8 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
VMSVGAFIFO_CHECK_3D_CMD_MIN_SIZE_BREAK(sizeof(*pCmd));
cMipLevels = (pHdr->size - sizeof(*pCmd)) / sizeof(SVGA3dSize);
- rc = vmsvga3dSurfaceDefine(pThis, pCmd->sid, (uint32_t)pCmd->surfaceFlags, pCmd->format, pCmd->face, 0, SVGA3D_TEX_FILTER_NONE, cMipLevels, (SVGA3dSize *)(pCmd + 1));
+ rc = vmsvga3dSurfaceDefine(pThis, pCmd->sid, (uint32_t)pCmd->surfaceFlags, pCmd->format, pCmd->face, 0,
+ SVGA3D_TEX_FILTER_NONE, cMipLevels, (SVGA3dSize *)(pCmd + 1));
# ifdef DEBUG_GMR_ACCESS
VMR3ReqCallWait(PDMDevHlpGetVM(pThis->pDevInsR3), VMCPUID_ANY, (PFNRT)vmsvgaResetGMRHandlers, 1, pThis);
# endif
@@ -2883,7 +3074,9 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
VMSVGAFIFO_CHECK_3D_CMD_MIN_SIZE_BREAK(sizeof(*pCmd));
cMipLevels = (pHdr->size - sizeof(*pCmd)) / sizeof(SVGA3dSize);
- rc = vmsvga3dSurfaceDefine(pThis, pCmd->sid, pCmd->surfaceFlags, pCmd->format, pCmd->face, pCmd->multisampleCount, pCmd->autogenFilter, cMipLevels, (SVGA3dSize *)(pCmd + 1));
+ rc = vmsvga3dSurfaceDefine(pThis, pCmd->sid, pCmd->surfaceFlags, pCmd->format, pCmd->face,
+ pCmd->multisampleCount, pCmd->autogenFilter,
+ cMipLevels, (SVGA3dSize *)(pCmd + 1));
break;
}
@@ -2911,7 +3104,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
SVGA3dCmdSurfaceStretchBlt *pCmd = (SVGA3dCmdSurfaceStretchBlt *)(pHdr + 1);
VMSVGAFIFO_CHECK_3D_CMD_MIN_SIZE_BREAK(sizeof(*pCmd));
- rc = vmsvga3dSurfaceStretchBlt(pThis, pCmd->dest, pCmd->boxDest, pCmd->src, pCmd->boxSrc, pCmd->mode);
+ rc = vmsvga3dSurfaceStretchBlt(pThis, &pCmd->dest, &pCmd->boxDest, &pCmd->src, &pCmd->boxSrc, pCmd->mode);
break;
}
@@ -2936,7 +3129,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
cRects = (pHdr->size - sizeof(*pCmd)) / sizeof(SVGASignedRect);
rc = vmsvga3dSurfaceBlitToScreen(pThis, pCmd->destScreenId, pCmd->destRect, pCmd->srcImage, pCmd->srcRect, cRects, (SVGASignedRect *)(pCmd + 1));
- break;
+ break;
}
case SVGA_3D_CMD_CONTEXT_DEFINE:
@@ -3063,6 +3256,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
}
case SVGA_3D_CMD_PRESENT:
+ case SVGA_3D_CMD_PRESENT_READBACK: /** @todo SVGA_3D_CMD_PRESENT_READBACK isn't quite the same as present... */
{
SVGA3dCmdPresent *pCmd = (SVGA3dCmdPresent *)(pHdr + 1);
VMSVGAFIFO_CHECK_3D_CMD_MIN_SIZE_BREAK(sizeof(*pCmd));
@@ -3265,7 +3459,7 @@ static DECLCALLBACK(int) vmsvgaFIFOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
*/
void vmsvgaGMRFree(PVGASTATE pThis, uint32_t idGMR)
{
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
/* Free the old descriptor if present. */
if (pSVGAState->aGMR[idGMR].numDescriptors)
@@ -3302,7 +3496,7 @@ void vmsvgaGMRFree(PVGASTATE pThis, uint32_t idGMR)
int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType, uint8_t *pbDst, int32_t cbDestPitch,
SVGAGuestPtr src, uint32_t offSrc, int32_t cbSrcPitch, uint32_t cbWidth, uint32_t cHeight)
{
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
PGMR pGMR;
int rc;
PVMSVGAGMRDESCRIPTOR pDesc;
@@ -3317,11 +3511,11 @@ int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType,
{
offSrc += src.offset;
AssertMsgReturn(src.offset < pThis->vram_size,
- ("src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x cbTotal=%#x vram_size=%#x\n",
+ ("src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x vram_size=%#x\n",
src.offset, offSrc, cbSrcPitch, cHeight, cbWidth, pThis->vram_size),
VERR_INVALID_PARAMETER);
AssertMsgReturn(offSrc + cbSrcPitch * (cHeight - 1) + cbWidth <= pThis->vram_size,
- ("src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x cbTotal=%#x vram_size=%#x\n",
+ ("src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x vram_size=%#x\n",
src.offset, offSrc, cbSrcPitch, cHeight, cbWidth, pThis->vram_size),
VERR_INVALID_PARAMETER);
@@ -3348,7 +3542,7 @@ int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType,
}
else
{
- for(uint32_t i = 0; i < cHeight; i++)
+ for(uint32_t i = 0; i < cHeight; i++)
{
memcpy(pbDst, pSrc, cbWidth);
@@ -3372,7 +3566,7 @@ int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType,
("src.gmrId=%#x src.offset=%#x offSrc=%#x cbSrcPitch=%#x cHeight=%#x cbWidth=%#x cbTotal=%#x\n",
src.gmrId, src.offset, offSrc, cbSrcPitch, cHeight, cbWidth, pGMR->cbTotal),
VERR_INVALID_PARAMETER);
-
+
for (uint32_t i = 0; i < cHeight; i++)
{
uint32_t cbCurrentWidth = cbWidth;
@@ -3395,7 +3589,7 @@ int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType,
{
cbToCopy = cbCurrentWidth;
}
- else
+ else
{
cbToCopy = (offDesc + pDesc->numPages * PAGE_SIZE - offCurrent);
AssertReturn(cbToCopy <= cbCurrentWidth, VERR_INVALID_PARAMETER);
@@ -3466,7 +3660,9 @@ static void vmsvgaSetTraces(PVGASTATE pThis, bool fTraces)
Log(("vmsvgaSetTraces: enable dirty page handling for the frame buffer only (%x bytes)\n", 0));
if (pThis->svga.uHeight != VMSVGA_VAL_UNINITIALIZED)
{
+#ifndef DEBUG_bird /* BB-10.3.1 triggers this as it initializes everything to zero. Better just ignore it. */
Assert(pThis->svga.cbScanline);
+#endif
/* Hardware enabled; return real framebuffer size .*/
cbFrameBuffer = (uint32_t)pThis->svga.uHeight * pThis->svga.cbScanline;
cbFrameBuffer = RT_ALIGN(cbFrameBuffer, PAGE_SIZE);
@@ -3580,15 +3776,144 @@ DECLCALLBACK(int) vmsvgaR3IORegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS
return VINF_SUCCESS;
}
+# ifdef VBOX_WITH_VMSVGA3D
+
+/**
+ * Used by vmsvga3dInfoSurfaceWorker to make the FIFO thread to save one or all
+ * surfaces to VMSVGA3DMIPMAPLEVEL::pSurfaceData heap buffers.
+ *
+ * @param pThis The VGA device instance data.
+ * @param sid Either UINT32_MAX or the ID of a specific
+ * surface. If UINT32_MAX is used, all surfaces
+ * are processed.
+ */
+void vmsvga3dSurfaceUpdateHeapBuffersOnFifoThread(PVGASTATE pThis, uint32_t sid)
+{
+ vmsvgaR3RunExtCmdOnFifoThread(pThis, VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS, (void *)(uintptr_t)sid,
+ sid == UINT32_MAX ? 10 * RT_MS_1SEC : RT_MS_1MIN);
+}
+
+
+/**
+ * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga3dsfc"}
+ */
+DECLCALLBACK(void) vmsvgaR3Info3dSurface(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+ /* There might be a specific context ID at the start of the
+ arguments, if not show all contexts. */
+ uint32_t cid = UINT32_MAX;
+ if (pszArgs)
+ pszArgs = RTStrStripL(pszArgs);
+ if (pszArgs && RT_C_IS_DIGIT(*pszArgs))
+ cid = RTStrToUInt32(pszArgs);
+
+ /* Verbose or terse display, we default to verbose. */
+ bool fVerbose = true;
+ if (RTStrIStr(pszArgs, "terse"))
+ fVerbose = false;
+
+ /* The size of the ascii art (x direction, y is 3/4 of x). */
+ uint32_t cxAscii = 80;
+ if (RTStrIStr(pszArgs, "gigantic"))
+ cxAscii = 300;
+ else if (RTStrIStr(pszArgs, "huge"))
+ cxAscii = 180;
+ else if (RTStrIStr(pszArgs, "big"))
+ cxAscii = 132;
+ else if (RTStrIStr(pszArgs, "normal"))
+ cxAscii = 80;
+ else if (RTStrIStr(pszArgs, "medium"))
+ cxAscii = 64;
+ else if (RTStrIStr(pszArgs, "small"))
+ cxAscii = 48;
+ else if (RTStrIStr(pszArgs, "tiny"))
+ cxAscii = 24;
+
+ /* Y invert the image when producing the ASCII art. */
+ bool fInvY = false;
+ if (RTStrIStr(pszArgs, "invy"))
+ fInvY = true;
+
+ vmsvga3dInfoSurfaceWorker(PDMINS_2_DATA(pDevIns, PVGASTATE), pHlp, cid, fVerbose, cxAscii, fInvY);
+}
+
+
+/**
+ * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga3dctx"}
+ */
+DECLCALLBACK(void) vmsvgaR3Info3dContext(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+ /* There might be a specific surface ID at the start of the
+ arguments, if not show all contexts. */
+ uint32_t sid = UINT32_MAX;
+ if (pszArgs)
+ pszArgs = RTStrStripL(pszArgs);
+ if (pszArgs && RT_C_IS_DIGIT(*pszArgs))
+ sid = RTStrToUInt32(pszArgs);
+
+ /* Verbose or terse display, we default to verbose. */
+ bool fVerbose = true;
+ if (RTStrIStr(pszArgs, "terse"))
+ fVerbose = false;
+
+ vmsvga3dInfoContextWorker(PDMINS_2_DATA(pDevIns, PVGASTATE), pHlp, sid, fVerbose);
+}
+
+# endif /* VBOX_WITH_VMSVGA3D */
+
+/**
+ * @callback_method_impl{FNDBGFHANDLERDEV, "vmsvga"}
+ */
+static DECLCALLBACK(void) vmsvgaR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
+
+ pHlp->pfnPrintf(pHlp, "Extension enabled: %RTbool\n", pThis->svga.fEnabled);
+ pHlp->pfnPrintf(pHlp, "Configured: %RTbool\n", pThis->svga.fConfigured);
+ pHlp->pfnPrintf(pHlp, "Base I/O port: %#x\n", pThis->svga.BasePort);
+ pHlp->pfnPrintf(pHlp, "FIFO address: %RGp\n", pThis->svga.GCPhysFIFO);
+ pHlp->pfnPrintf(pHlp, "FIFO size: %u (%#x)\n", pThis->svga.cbFIFO, pThis->svga.cbFIFO);
+ pHlp->pfnPrintf(pHlp, "FIFO external cmd: %#x\n", pThis->svga.u8FIFOExtCommand);
+ pHlp->pfnPrintf(pHlp, "FIFO extcmd wakeup: %u\n", pThis->svga.fFifoExtCommandWakeup);
+ pHlp->pfnPrintf(pHlp, "Busy: %#x\n", pThis->svga.fBusy);
+ pHlp->pfnPrintf(pHlp, "Traces: %RTbool (effective: %RTbool)\n", pThis->svga.fTraces, pThis->svga.fVRAMTracking);
+ pHlp->pfnPrintf(pHlp, "Guest ID: %#x (%d)\n", pThis->svga.u32GuestId, pThis->svga.u32GuestId);
+ pHlp->pfnPrintf(pHlp, "IRQ status: %#x\n", pThis->svga.u32IrqStatus);
+ pHlp->pfnPrintf(pHlp, "IRQ mask: %#x\n", pThis->svga.u32IrqMask);
+ pHlp->pfnPrintf(pHlp, "Pitch lock: %#x\n", pThis->svga.u32PitchLock);
+ pHlp->pfnPrintf(pHlp, "Current GMR ID: %#x\n", pThis->svga.u32CurrentGMRId);
+ pHlp->pfnPrintf(pHlp, "Capabilites reg: %#x\n", pThis->svga.u32RegCaps);
+ pHlp->pfnPrintf(pHlp, "Index reg: %#x\n", pThis->svga.u32IndexReg);
+ pHlp->pfnPrintf(pHlp, "Action flags: %#x\n", pThis->svga.u32ActionFlags);
+ pHlp->pfnPrintf(pHlp, "Max display size: %ux%u\n", pThis->svga.u32MaxWidth, pThis->svga.u32MaxHeight);
+ pHlp->pfnPrintf(pHlp, "Display size: %ux%u %ubpp\n", pThis->svga.uWidth, pThis->svga.uHeight, pThis->svga.uBpp);
+ pHlp->pfnPrintf(pHlp, "Scanline: %u (%#x)\n", pThis->svga.cbScanline, pThis->svga.cbScanline);
+ pHlp->pfnPrintf(pHlp, "Viewport position: %ux%u\n", pThis->svga.viewport.x, pThis->svga.viewport.y);
+ pHlp->pfnPrintf(pHlp, "Viewport size: %ux%u\n", pThis->svga.viewport.cx, pThis->svga.viewport.cy);
+
+ pHlp->pfnPrintf(pHlp, "Cursor active: %RTbool\n", pSVGAState->Cursor.fActive);
+ pHlp->pfnPrintf(pHlp, "Cursor hotspot: %ux%u\n", pSVGAState->Cursor.xHotspot, pSVGAState->Cursor.yHotspot);
+ pHlp->pfnPrintf(pHlp, "Cursor size: %ux%u\n", pSVGAState->Cursor.width, pSVGAState->Cursor.height);
+ pHlp->pfnPrintf(pHlp, "Cursor byte size: %u (%#x)\n", pSVGAState->Cursor.cbData, pSVGAState->Cursor.cbData);
+
+# ifdef VBOX_WITH_VMSVGA3D
+ pHlp->pfnPrintf(pHlp, "3D enabled: %RTbool\n", pThis->svga.f3DEnabled);
+ pHlp->pfnPrintf(pHlp, "Host windows ID: %#RX64\n", pThis->svga.u64HostWindowId);
+ if (pThis->svga.u64HostWindowId != 0)
+ vmsvga3dInfoHostWindow(pHlp, pThis->svga.u64HostWindowId);
+# endif
+}
+
/**
* @copydoc FNSSMDEVLOADEXEC
*/
int vmsvgaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
- int rc;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
+ int rc;
/* Load our part of the VGAState */
rc = SSMR3GetStructEx(pSSM, &pThis->svga, sizeof(pThis->svga), 0, g_aVGAStateSVGAFields, NULL);
@@ -3599,7 +3924,7 @@ int vmsvgaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint3
AssertRCReturn(rc, rc);
/* Load the VMSVGA state. */
- rc = SSMR3GetStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGASTATEFields, NULL);
+ rc = SSMR3GetStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGAR3STATEFields, NULL);
AssertRCReturn(rc, rc);
/* Load the active cursor bitmaps. */
@@ -3618,7 +3943,7 @@ int vmsvgaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint3
PGMR pGMR = &pSVGAState->aGMR[i];
rc = SSMR3GetStructEx(pSSM, pGMR, sizeof(*pGMR), 0, g_aGMRFields, NULL);
- AssertRCReturn(rc, rc);
+ AssertRCReturn(rc, rc);
if (pGMR->numDescriptors)
{
@@ -3638,24 +3963,16 @@ int vmsvgaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint3
# ifdef VBOX_WITH_VMSVGA3D
if (pThis->svga.f3DEnabled)
{
- VMSVGA_STATE_LOAD loadstate;
-
- loadstate.pSSM = pSSM;
- loadstate.uVersion = uVersion;
- loadstate.uPass = uPass;
+# ifdef RT_OS_DARWIN /** @todo r=bird: this is normally done on the EMT, so for DARWIN we do that when loading saved state too now. See DevVGA-SVGA3d-shared.h. */
+ vmsvga3dPowerOn(pThis);
+# endif
- /* Save the 3d state in the FIFO thread. */
- pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_LOADSTATE;
- pThis->svga.pFIFOExtCmdParam = (void *)&loadstate;
- /* Hack alert: resume the IO thread as it has been suspended before the destruct callback.
- * The PowerOff notification isn't working, so not an option in this case.
- */
- PDMR3ThreadResume(pThis->svga.pFIFOIOThread);
- SUPSemEventSignal(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem);
- /* Wait for the end of the command. */
- rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, RT_INDEFINITE_WAIT);
- AssertRC(rc);
- PDMR3ThreadSuspend(pThis->svga.pFIFOIOThread);
+ VMSVGA_STATE_LOAD LoadState;
+ LoadState.pSSM = pSSM;
+ LoadState.uVersion = uVersion;
+ LoadState.uPass = uPass;
+ rc = vmsvgaR3RunExtCmdOnFifoThread(pThis, VMSVGA_FIFO_EXTCMD_LOADSTATE, &LoadState, RT_INDEFINITE_WAIT);
+ AssertLogRelRCReturn(rc, rc);
}
# endif
@@ -3667,8 +3984,8 @@ int vmsvgaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint3
*/
int vmsvgaLoadDone(PPDMDEVINS pDevIns)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
pThis->last_bpp = VMSVGA_VAL_UNINITIALIZED; /* force mode reset */
vmsvgaChangeMode(pThis);
@@ -3678,14 +3995,14 @@ int vmsvgaLoadDone(PPDMDEVINS pDevIns)
{
int rc;
- rc = pThis->pDrv->pfnVBVAMousePointerShape (pThis->pDrv,
- true,
- true,
- pSVGAState->Cursor.xHotspot,
- pSVGAState->Cursor.yHotspot,
- pSVGAState->Cursor.width,
- pSVGAState->Cursor.height,
- pSVGAState->Cursor.pData);
+ rc = pThis->pDrv->pfnVBVAMousePointerShape(pThis->pDrv,
+ true,
+ true,
+ pSVGAState->Cursor.xHotspot,
+ pSVGAState->Cursor.yHotspot,
+ pSVGAState->Cursor.width,
+ pSVGAState->Cursor.height,
+ pSVGAState->Cursor.pData);
AssertRC(rc);
}
return VINF_SUCCESS;
@@ -3696,57 +4013,50 @@ int vmsvgaLoadDone(PPDMDEVINS pDevIns)
*/
int vmsvgaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
- int rc;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
+ int rc;
/* Save our part of the VGAState */
rc = SSMR3PutStructEx(pSSM, &pThis->svga, sizeof(pThis->svga), 0, g_aVGAStateSVGAFields, NULL);
- AssertRCReturn(rc, rc);
+ AssertLogRelRCReturn(rc, rc);
/* Save the framebuffer backup. */
rc = SSMR3PutMem(pSSM, pThis->svga.pFrameBufferBackup, VMSVGA_FRAMEBUFFER_BACKUP_SIZE);
- AssertRCReturn(rc, rc);
+ AssertLogRelRCReturn(rc, rc);
/* Save the VMSVGA state. */
- rc = SSMR3PutStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGASTATEFields, NULL);
- AssertRCReturn(rc, rc);
+ rc = SSMR3PutStructEx(pSSM, pSVGAState, sizeof(*pSVGAState), 0, g_aVMSVGAR3STATEFields, NULL);
+ AssertLogRelRCReturn(rc, rc);
/* Save the active cursor bitmaps. */
if (pSVGAState->Cursor.fActive)
{
rc = SSMR3PutMem(pSSM, pSVGAState->Cursor.pData, pSVGAState->Cursor.cbData);
- AssertRCReturn(rc, rc);
+ AssertLogRelRCReturn(rc, rc);
}
/* Save the GMR state */
for (uint32_t i = 0; i < RT_ELEMENTS(pSVGAState->aGMR); i++)
{
rc = SSMR3PutStructEx(pSSM, &pSVGAState->aGMR[i], sizeof(pSVGAState->aGMR[i]), 0, g_aGMRFields, NULL);
- AssertRCReturn(rc, rc);
+ AssertLogRelRCReturn(rc, rc);
for (uint32_t j = 0; j < pSVGAState->aGMR[i].numDescriptors; j++)
{
rc = SSMR3PutStructEx(pSSM, &pSVGAState->aGMR[i].paDesc[j], sizeof(pSVGAState->aGMR[i].paDesc[j]), 0, g_aVMSVGAGMRDESCRIPTORFields, NULL);
- AssertRCReturn(rc, rc);
+ AssertLogRelRCReturn(rc, rc);
}
}
# ifdef VBOX_WITH_VMSVGA3D
+ /*
+ * Must save the 3d state in the FIFO thread.
+ */
if (pThis->svga.f3DEnabled)
{
- /* Save the 3d state in the FIFO thread. */
- pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_SAVESTATE;
- pThis->svga.pFIFOExtCmdParam = (void *)pSSM;
- /* Hack alert: resume the IO thread as it has been suspended before the destruct callback.
- * The PowerOff notification isn't working, so not an option in this case.
- */
- PDMR3ThreadResume(pThis->svga.pFIFOIOThread);
- SUPSemEventSignal(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem);
- /* Wait for the end of the external command. */
- rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, RT_INDEFINITE_WAIT);
- AssertRC(rc);
- PDMR3ThreadSuspend(pThis->svga.pFIFOIOThread);
+ rc = vmsvgaR3RunExtCmdOnFifoThread(pThis, VMSVGA_FIFO_EXTCMD_SAVESTATE, pSSM, RT_INDEFINITE_WAIT);
+ AssertLogRelRCReturn(rc, rc);
}
# endif
return VINF_SUCCESS;
@@ -3760,8 +4070,8 @@ int vmsvgaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
*/
int vmsvgaReset(PPDMDEVINS pDevIns)
{
- PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
/* Reset before init? */
if (!pSVGAState)
@@ -3769,19 +4079,16 @@ int vmsvgaReset(PPDMDEVINS pDevIns)
Log(("vmsvgaReset\n"));
- pThis->svga.pFIFOR3[SVGA_FIFO_NEXT_CMD] = pThis->svga.pFIFOR3[SVGA_FIFO_STOP] = 0;
- /* Reset the FIFO thread. */
- pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_RESET;
- SUPSemEventSignal(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem);
- /* Wait for the end of the termination sequence. */
- int rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, 10000);
- AssertRC(rc);
+ /* Reset the FIFO processing as well as the 3d state (if we have one). */
+ pThis->svga.pFIFOR3[SVGA_FIFO_NEXT_CMD] = pThis->svga.pFIFOR3[SVGA_FIFO_STOP] = 0; /** @todo should probably let the FIFO thread do this ... */
+ int rc = vmsvgaR3RunExtCmdOnFifoThread(pThis, VMSVGA_FIFO_EXTCMD_RESET, NULL /*pvParam*/, 10000 /*ms*/);
+ /* Reset other stuff. */
pThis->svga.cScratchRegion = VMSVGA_SCRATCH_SIZE;
- memset(pThis->svga.au32ScratchRegion, 0, sizeof(pThis->svga.au32ScratchRegion));
- memset(pThis->svga.pSVGAState, 0, sizeof(VMSVGASTATE));
- memset(pThis->svga.pFrameBufferBackup, 0, VMSVGA_FRAMEBUFFER_BACKUP_SIZE);
+ RT_ZERO(pThis->svga.au32ScratchRegion);
+ RT_ZERO(*pThis->svga.pSvgaR3State);
+ RT_BZERO(pThis->svga.pFrameBufferBackup, VMSVGA_FRAMEBUFFER_BACKUP_SIZE);
/* Register caps. */
pThis->svga.u32RegCaps = SVGA_CAP_GMR | SVGA_CAP_GMR2 | SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 | SVGA_CAP_EXTENDED_FIFO | SVGA_CAP_IRQMASK | SVGA_CAP_PITCHLOCK | SVGA_CAP_TRACES | SVGA_CAP_SCREEN_OBJECT_2 | SVGA_CAP_ALPHA_CURSOR;
@@ -3817,22 +4124,24 @@ int vmsvgaReset(PPDMDEVINS pDevIns)
int vmsvgaDestruct(PPDMDEVINS pDevIns)
{
PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
- int rc;
- /* Stop the FIFO thread. */
- pThis->svga.u8FIFOExtCommand = VMSVGA_FIFO_EXTCMD_TERMINATE;
- /* Hack alert: resume the IO thread as it has been suspended before the destruct callback.
- * The PowerOff notification isn't working, so not an option in this case.
+ /*
+ * Ask the FIFO thread to terminate the 3d state and then terminate it.
*/
- PDMR3ThreadResume(pThis->svga.pFIFOIOThread);
- SUPSemEventSignal(pThis->svga.pSupDrvSession, pThis->svga.FIFORequestSem);
+ if (pThis->svga.pFIFOIOThread)
+ {
+ int rc = vmsvgaR3RunExtCmdOnFifoThread(pThis, VMSVGA_FIFO_EXTCMD_TERMINATE, NULL /*pvParam*/, 30000 /*ms*/);
+ AssertLogRelRC(rc);
- /* Wait for the end of the termination sequence. */
- rc = RTSemEventWait(pThis->svga.FIFOExtCmdSem, 10000);
- AssertRC(rc);
- PDMR3ThreadSuspend(pThis->svga.pFIFOIOThread);
+ rc = PDMR3ThreadDestroy(pThis->svga.pFIFOIOThread, NULL);
+ AssertLogRelRC(rc);
+ pThis->svga.pFIFOIOThread = NULL;
+ }
+ /*
+ * Destroy the special SVGA state.
+ */
+ PVMSVGAR3STATE pSVGAState = pThis->svga.pSvgaR3State;
if (pSVGAState)
{
# ifndef VMSVGA_USE_EMT_HALT_CODE
@@ -3846,12 +4155,16 @@ int vmsvgaDestruct(PPDMDEVINS pDevIns)
RTMemFree(pSVGAState->Cursor.pData);
for (unsigned i = 0; i < RT_ELEMENTS(pSVGAState->aGMR); i++)
- {
if (pSVGAState->aGMR[i].paDesc)
RTMemFree(pSVGAState->aGMR[i].paDesc);
- }
+
RTMemFree(pSVGAState);
+ pThis->svga.pSvgaR3State = NULL;
}
+
+ /*
+ * Free our resources residing in the VGA state.
+ */
if (pThis->svga.pFrameBufferBackup)
RTMemFree(pThis->svga.pFrameBufferBackup);
if (pThis->svga.FIFOExtCmdSem != NIL_RTSEMEVENT)
@@ -3877,16 +4190,16 @@ int vmsvgaDestruct(PPDMDEVINS pDevIns)
int vmsvgaInit(PPDMDEVINS pDevIns)
{
PVGASTATE pThis = PDMINS_2_DATA(pDevIns, PVGASTATE);
- PVMSVGASTATE pSVGAState;
+ PVMSVGAR3STATE pSVGAState;
PVM pVM = PDMDevHlpGetVM(pDevIns);
int rc;
pThis->svga.cScratchRegion = VMSVGA_SCRATCH_SIZE;
memset(pThis->svga.au32ScratchRegion, 0, sizeof(pThis->svga.au32ScratchRegion));
- pThis->svga.pSVGAState = RTMemAllocZ(sizeof(VMSVGASTATE));
- AssertReturn(pThis->svga.pSVGAState, VERR_NO_MEMORY);
- pSVGAState = (PVMSVGASTATE)pThis->svga.pSVGAState;
+ pThis->svga.pSvgaR3State = (PVMSVGAR3STATE)RTMemAllocZ(sizeof(VMSVGAR3STATE));
+ AssertReturn(pThis->svga.pSvgaR3State, VERR_NO_MEMORY);
+ pSVGAState = pThis->svga.pSvgaR3State;
/* Necessary for creating a backup of the text mode frame buffer when switching into svga mode. */
pThis->svga.pFrameBufferBackup = RTMemAllocZ(VMSVGA_FRAMEBUFFER_BACKUP_SIZE);
@@ -3980,7 +4293,19 @@ int vmsvgaInit(PPDMDEVINS pDevIns)
STAM_REL_REG(pVM, &pSVGAState->StatFifoTodoTimeout, STAMTYPE_COUNTER, "/Devices/VMSVGA/FifoTodoTimeout", STAMUNIT_OCCURENCES, "Number of times we discovered pending work after a wait timeout.");
STAM_REL_REG(pVM, &pSVGAState->StatFifoTodoWoken, STAMTYPE_COUNTER, "/Devices/VMSVGA/FifoTodoWoken", STAMUNIT_OCCURENCES, "Number of times we discovered pending work after being woken up.");
STAM_REL_REG(pVM, &pSVGAState->StatFifoStalls, STAMTYPE_PROFILE, "/Devices/VMSVGA/FifoStalls", STAMUNIT_TICKS_PER_CALL, "Profiling of FIFO stalls (waiting for guest to finish copying data).");
-
+
+ /*
+ * Info handlers.
+ */
+ PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga", "Basic VMSVGA device state details", vmsvgaR3Info);
+# ifdef VBOX_WITH_VMSVGA3D
+ PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga3dctx", "VMSVGA 3d context details. Accepts 'terse'.", vmsvgaR3Info3dContext);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "vmsvga3dsfc",
+ "VMSVGA 3d surface details. "
+ "Accepts 'terse', 'invy', and one of 'tiny', 'medium', 'normal', 'big', 'huge', or 'gigantic'.",
+ vmsvgaR3Info3dSurface);
+# endif
+
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA.h b/src/VBox/Devices/Graphics/DevVGA-SVGA.h
index b720a25..cbad581 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA.h
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA.h
@@ -29,13 +29,20 @@
#define VMSVGA_VAL_UNINITIALIZED (unsigned)-1
+/** For validating X and width values.
+ * The code assumes it's at least an order of magnitude less than UINT32_MAX. */
+#define VMSVGA_MAX_X _1M
+/** For validating Y and height values.
+ * The code assumes it's at least an order of magnitude less than UINT32_MAX. */
+#define VMSVGA_MAX_Y _1M
+
/* u32ActionFlags */
#define VMSVGA_ACTION_CHANGEMODE_BIT 0
#define VMSVGA_ACTION_CHANGEMODE RT_BIT(VMSVGA_ACTION_CHANGEMODE_BIT)
DECLCALLBACK(int) vmsvgaR3IORegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType);
-DECLCALLBACK(void) vmsvgaPortSetViewPort(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
+DECLCALLBACK(void) vmsvgaPortSetViewport(PPDMIDISPLAYPORT pInterface, uint32_t uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy);
int vmsvgaInit(PPDMDEVINS pDevIns);
int vmsvgaReset(PPDMDEVINS pDevIns);
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.h b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.h
index a48f022..f152616 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.h
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.h
@@ -1,3 +1,4 @@
+/* $Id: DevVGA-SVGA3d-cocoa.h $ */
/** @file
* VirtualBox OpenGL Cocoa Window System Helper Implementation.
*/
@@ -17,7 +18,7 @@
#ifndef __DevVGA_SVGA3d_cocoa_h
#define __DevVGA_SVGA3d_cocoa_h
-#include <iprt/types.h>
+#include <VBox/types.h>
#include <VBox/VBoxCocoa.h>
RT_C_DECLS_BEGIN
@@ -38,11 +39,15 @@ VMSVGA3DCOCOA_DECL(bool) vmsvga3dCocoaCreateViewAndContext(NativeNSViewRef *ppVi
NativeNSViewRef pParentView, uint32_t cx, uint32_t cy,
NativeNSOpenGLContextRef pSharedCtx, bool fOtherProfile);
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx);
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewInfo(PCDBGFINFOHLP pHlp, NativeNSViewRef pView);
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y);
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int w, int h);
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewUpdateViewport(NativeNSViewRef pView);
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx);
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx);
+int ExplicitlyLoadVBoxSVGA3DObjC(bool fResolveAllImports, PRTERRINFO pErrInfo);
+
RT_C_DECLS_END
#endif /* !__DevVGA_SVGA3d_cocoa_h */
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m
index e494920..c27498a 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m
@@ -1,7 +1,7 @@
/* $Id: DevVGA-SVGA3d-cocoa.m $ */
/** @file
- * VirtualBox OpenGL Cocoa Window System Helper Implementation.
- *
+ * VirtualBox OpenGL Cocoa Window System Helper Implementation.
+ *
* @remarks Inspired by HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m.
*/
@@ -17,35 +17,47 @@
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
#include "DevVGA-SVGA3d-cocoa.h"
#import <Cocoa/Cocoa.h>
+#undef PVM /* Stupid namespace pollution from outdated sys/param.h header file. */
#import <OpenGL/gl.h>
#include <iprt/thread.h>
#include <iprt/assert.h>
#include <iprt/string.h>
#include <VBox/log.h>
+#include <VBox/vmm/dbgf.h>
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
/** @def USE_NSOPENGLVIEW
- * Define this to experiment with using NSOpenGLView instead
- * of NSView. There are transparency issues with the former,
+ * Define this to experiment with using NSOpenGLView instead
+ * of NSView. There are transparency issues with the former,
* so for the time being we're using the latter. */
#if 0
#define USE_NSOPENGLVIEW
#endif
+/**@def FLOAT_FMT_STR
+ * Format string bits to go with FLOAT_FMT_ARGS. */
+#define FLOAT_FMT_STR "%d.%06d"
+/** @def FLOAT_FMT_ARGS
+ * Format arguments for a float value, corresponding to FLOAT_FMT_STR.
+ * @param r The floating point value to format. */
+#define FLOAT_FMT_ARGS(r) (int)(r), ((unsigned)((r) * 1000000) % 1000000U)
+
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
/**
* Argument package for doing this on the main thread.
*/
@@ -53,7 +65,7 @@
{
@public
/* in */
- NativeNSViewRef pParentView;
+ NativeNSViewRef pParentView;
uint32_t cx;
uint32_t cy;
NativeNSOpenGLContextRef pSharedCtx;
@@ -69,7 +81,7 @@
/**
* The overlay view.
*/
- at interface VMSVGA3DOverlayView
+ at interface VMSVGA3DOverlayView
#ifdef USE_NSOPENGLVIEW
: NSOpenGLView
#else
@@ -77,28 +89,44 @@
#endif
{
@private
- NSView *m_pParentView;
- /** Set if the buffers needs clearing. */
- bool m_fClear;
+ /** This points to the parent view, if there is one. If there isn't a parent
+ * the view will be hidden and never used for displaying stuff. We only have
+ * one visible context per guest screen that is visible to the user and
+ * subject to buffer swapping. */
+ NSView *m_pParentView;
+ /** Indicates that buffers (back+front) needs clearing before use because
+ * the view changed size. There are two buffers, so this is set to two
+ * each time when the view area increases. */
+ uint32_t m_cClears;
+ /** Set if the OpenGL context needs updating after a resize. */
+ bool m_fUpdateCtx;
#ifndef USE_NSOPENGLVIEW
/** The OpenGL context associated with this view. */
NSOpenGLContext *m_pCtx;
+ /** Number of times we've tried to set the view (shut up noisy NSLog). */
+ uint32_t m_cSetViewAttempts;
#endif
- /* Position/Size tracking */
- NSPoint m_Pos;
- NSSize m_Size;
-
- /** This is necessary for clipping on the root window */
- NSRect m_RootRect;
+ /** The desired view position relative to super. */
+ NSPoint m_Pos;
+ /** The desired view size. */
+ NSSize m_Size;
}
+ (void)createViewAndContext:(VMSVGA3DCreateViewAndContext *)pParams;
- (id)initWithFrameAndFormat:(NSRect)frame parentView:(NSView*)pparentView pixelFormat:(NSOpenGLPixelFormat *)pFmt;
-- (void)setPos:(NSPoint)pos;
-- (void)setSize:(NSSize)size;
+- (void)vboxSetPos:(NSPoint)pos;
+- (void)vboxSetSize:(NSSize)size;
+- (void)vboxScheduleCtxUpdate;
+- (void)vboxReshapePerform;
- (void)vboxReshape;
-- (void)vboxClearBuffers;
+- (void)vboxBoundsDidChange:(NSNotification *)pNotification;
+- (void)vboxFrameDidChange:(NSNotification *)pNotification;
+- (void)vboxFrameDidChangeGlobal:(NSNotification *)pNotification;
+- (BOOL)postsFrameChangedNotifications;
+- (void)vboxRemoveFromSuperviewAndHide;
+- (void)vboxUpdateCtxIfNecessary;
+- (void)vboxClearBackBufferIfNecessary;
- (NSOpenGLContext *)makeCurrentGLContext;
- (void)restoreSavedGLContext:(NSOpenGLContext *)pSavedCtx;
@@ -109,7 +137,7 @@
- (void)prepareOpenGL;
#endif
-/* Overridden: */
+/* Overridden: */
- (void)viewDidMoveToWindow;
- (void)viewDidMoveToSuperview;
- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize;
@@ -128,7 +156,7 @@
+ (void)createViewAndContext:(VMSVGA3DCreateViewAndContext *)pParams
{
- LogFlow(("OvlWin createViewAndContext:\n"));
+ LogFlow(("OvlView createViewAndContext:\n"));
/*
* Create a pixel format.
@@ -158,16 +186,16 @@
NSRect Frame;
Frame.origin.x = 0;
Frame.origin.y = 0;
- Frame.size.width = pParams->cx < _1M ? pParams->cx : 0;
- Frame.size.height = pParams->cy < _1M ? pParams->cy : 0;
+ Frame.size.width = pParams->cx < _1M && pParams->cx > 0 ? pParams->cx : 1; /* 'invalid drawable' if 0,0 size? */
+ Frame.size.height = pParams->cy < _1M && pParams->cy > 0 ? pParams->cy : 1;
VMSVGA3DOverlayView *pView = [[VMSVGA3DOverlayView alloc] initWithFrameAndFormat:Frame
parentView:pParams->pParentView
pixelFormat:pFmt];
if (pView)
{
/*
- * If we have no shared GL context, we use the one that NSOpenGLView create. Otherwise,
- * we replace it. (If we don't call openGLContext, it won't yet have been instantiated,
+ * If we have no shared GL context, we use the one that NSOpenGLView create. Otherwise,
+ * we replace it. (If we don't call openGLContext, it won't yet have been instantiated,
* so there is no unecessary contexts created here when pSharedCtx != NULL.)
*/
NSOpenGLContext *pCtx;
@@ -189,15 +217,18 @@
}
if (pCtx)
{
- /*
- * Attach the view to the parent.
+ /*
+ * Attach the view to the parent if we have one. Otherwise make sure its invisible.
*/
- [pParams->pParentView addSubview:pView];
+ if (pParams->pParentView)
+ [pParams->pParentView addSubview:pView];
+ else
+ [pView setHidden:YES];
/*
* Resize and return.
*/
- //[pView setSize:Frame.size];
+ //[pView vboxSetSize:Frame.size];
NSOpenGLContext *pSavedCtx = [pView makeCurrentGLContext];
@@ -207,7 +238,10 @@
//x = 1; [pCtx setValues:&x forParameter:NSOpenGLCPSurfaceOrder];
x = 0; [pCtx setValues:&x forParameter:NSOpenGLCPSurfaceOpacity];
- [pView setHidden:NO];
+ if (pParams->pParentView)
+ [pView setHidden:NO];
+ else
+ [pView setHidden:YES];
[pView restoreSavedGLContext:pSavedCtx];
@@ -216,7 +250,8 @@
[pCtx retain]; //??
[pFmt release];
- LogFlow(("OvlWin createViewAndContext: returns successfully\n"));
+
+ LogFlow(("OvlView createViewAndContext: returns successfully\n"));
return;
}
[pView release];
@@ -226,36 +261,64 @@
else
AssertFailed();
- LogFlow(("OvlWin createViewAndContext: returns failure\n"));
+ LogFlow(("OvlView createViewAndContext: returns failure\n"));
return;
}
-- (id)initWithFrameAndFormat:(NSRect) frame parentView:(NSView*)pParentView pixelFormat:(NSOpenGLPixelFormat *)pFmt
+- (id)initWithFrameAndFormat:(NSRect) frame parentView:(NSView *)pParentView pixelFormat:(NSOpenGLPixelFormat *)pFmt
{
- LogFlow(("OvlWin(%p) initWithFrameAndFormat:\n", (void *)self));
+ LogFlow(("OvlView(%p) initWithFrameAndFormat:\n", (void *)self));
m_pParentView = pParentView;
/* Make some reasonable defaults */
m_Pos = NSZeroPoint;
m_Size = frame.size;
- m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
-
+ m_cClears = 2;
+ m_fUpdateCtx = true;
+
#ifdef USE_NSOPENGLVIEW
self = [super initWithFrame:frame pixelFormat:pFmt];
#else
+ m_cSetViewAttempts = 0;
+ m_pCtx = NULL;
self = [super initWithFrame:frame];
#endif
if (self)
{
- self.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin;
+ //self.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin;
+ self.autoresizingMask = NSViewNotSizable;
+
+ /*
+ * Get notifications when we're moved or resized and when we're moved
+ * to a different screen or GPU or when the GL context simply needs updating.
+ */
+ if (pParentView)
+ {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(vboxBoundsDidChange:)
+ name:NSViewBoundsDidChangeNotification
+ object:self];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(vboxFrameDidChange:)
+ name:NSViewFrameDidChangeNotification
+ object:self];
+ //[[NSNotificationCenter defaultCenter] addObserver:self
+ // selector:@selector(vboxFrameDidChange:)
+ // name:NSViewDidUpdateTrackingAreasNotification
+ // object:self];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(vboxFrameDidChangeGlobal:)
+ name:NSViewGlobalFrameDidChangeNotification
+ object:self];
+ }
}
- LogFlow(("OvlWin(%p) initWithFrameAndFormat: returns %p\n", (void *)self, (void *)self));
+ LogFlow(("OvlView(%p) initWithFrameAndFormat: returns %p\n", (void *)self, (void *)self));
return self;
}
- (void)dealloc
{
- LogFlow(("OvlWin(%p) dealloc:\n", (void *)self));
+ LogFlow(("OvlView(%p) dealloc:\n", (void *)self));
#ifdef USE_NSOPENGLVIEW
[[self openGLContext] clearDrawable];
@@ -270,79 +333,228 @@
[super dealloc];
- LogFlow(("OvlWin(%p) dealloc: returns\n", (void *)self));
+ LogFlow(("OvlView(%p) dealloc: returns\n", (void *)self));
}
-- (void)setPos:(NSPoint)pos
+- (void)vboxSetPos:(NSPoint)pos
{
- Log(("OvlWin(%p) setPos: (%d,%d)\n", (void *)self, (int)pos.x, (int)pos.y));
+ Log(("OvlView(%p) vboxSetPos: (%d,%d)\n", (void *)self, (int)pos.x, (int)pos.y));
m_Pos = pos;
[self vboxReshape];
- LogFlow(("OvlWin(%p) setPos: returns\n", (void *)self));
+ LogFlow(("OvlView(%p) vboxSetPos: returns\n", (void *)self));
}
-- (void)setSize:(NSSize)size
+- (void)vboxSetSize:(NSSize)size
{
- Log(("OvlWin(%p) setSize: (%d,%d):\n", (void *)self, (int)size.width, (int)size.height));
+ Log(("OvlView(%p) vboxSetSize: (%d,%d):\n", (void *)self, (int)size.width, (int)size.height));
m_Size = size;
[self vboxReshape];
- LogFlow(("OvlWin(%p) setSize: returns\n", (void *)self));
+ LogFlow(("OvlView(%p) vboxSetSize: returns\n", (void *)self));
+}
+
+- (void)vboxScheduleCtxUpdate
+{
+ m_fUpdateCtx = true;
}
+- (void)vboxUpdateCtxIfNecessary
+{
+ if (m_fUpdateCtx)
+ {
+ Log(("OvlView(%p) vboxUpdateCtxIfNecessary: m_fUpdateCtx\n", (void *)self));
+ [[self openGLContext] update];
+ m_fUpdateCtx = false;
+ }
+}
-- (void)vboxClearBuffers
+
+- (void)vboxClearBackBufferIfNecessary
{
#if 1 /* experiment */
- if ([NSThread isMainThread])
- Log(("OvlWin(%p) vboxClearBuffers: skip, main thread\n", (void *)self));
- else
+ if (m_cClears > 0)
{
- Log(("OvlWin(%p) vboxClearBuffers: clears\n", (void *)self));
- NSOpenGLContext *pSavedCtx = [self makeCurrentGLContext];
+ Assert(![NSThread isMainThread]);
+ Assert([self openGLContext] == [NSOpenGLContext currentContext]);
+ Log(("OvlView(%p) vboxClearBackBufferIfNecessary: m_cClears=%d\n", (void *)self, m_cClears));
+ m_cClears--;
+
+ /* Clear errors. */
+ GLenum rc;
+ while ((rc = glGetError()) != GL_NO_ERROR)
+ continue;
+ /* Save the old buffer setting and make it GL_BACK (shall be GL_BACK already actually). */
GLint iOldDrawBuf = GL_BACK;
glGetIntegerv(GL_DRAW_BUFFER, &iOldDrawBuf);
- glDrawBuffer(GL_FRONT_AND_BACK);
+ if (iOldDrawBuf != GL_BACK)
+ glDrawBuffer(GL_BACK);
+ while ((rc = glGetError()) != GL_NO_ERROR)
+ AssertMsgFailed(("rc=%x\n", rc));
+
+ /* Clear the current GL_BACK. */
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT /*|GL_DEPTH_BUFFER_BIT*/ );
- [[self openGLContext] flushBuffer];
- glDrawBuffer(iOldDrawBuf);
+ while ((rc = glGetError()) != GL_NO_ERROR)
+ AssertMsgFailed(("rc=%x\n", rc));
+
+ /* We're back to the orignal back buffer now. Just restore GL_DRAW_BUFFER. */
+ if (iOldDrawBuf != GL_BACK)
+ glDrawBuffer(iOldDrawBuf);
- [self restoreSavedGLContext:pSavedCtx];
+ while ((rc = glGetError()) != GL_NO_ERROR)
+ AssertMsgFailed(("rc=%x\n", rc));
}
#endif
}
-- (void)vboxReshape
-{
- LogFlow(("OvlWin(%p) vboxReshape:\n", (void *)self));
+- (void)vboxReshapePerform
+{
/*
- * Not doing any complicate stuff here yet, hoping that we'll get correctly
- * resized when the parent view changes...
+ * Change the size and position if necessary.
*/
+ NSRect CurFrameRect = [self frame];
+ /** @todo conversions? */
+ if ( m_Pos.x != CurFrameRect.origin.x
+ || m_Pos.y != CurFrameRect.origin.y)
+ {
+ LogFlow(("OvlView(%p) vboxReshapePerform: moving (%d,%d) -> (%d,%d)\n",
+ (void *)self, CurFrameRect.origin.x, CurFrameRect.origin.y, m_Pos.x, m_Pos.y));
+ [self setFrameOrigin:m_Pos];
+ }
+
+ if ( CurFrameRect.size.width != m_Size.width
+ || CurFrameRect.size.height != m_Size.height)
+ {
+ LogFlow(("OvlView(%p) vboxReshapePerform: resizing (%d,%d) -> (%d,%d)\n",
+ (void *)self, CurFrameRect.size.width, CurFrameRect.size.height, m_Size.width, m_Size.height));
+ [self setFrameSize:m_Size];
+
+ /*
+ * Schedule two clears and a context update for now.
+ * Really though, we should just clear any new surface area.
+ */
+ m_cClears = 2;
+ }
+ m_fUpdateCtx = true;
+ LogFlow(("OvlView(%p) vboxReshapePerform: returns\n", self));
+}
+
+
+- (void)vboxReshape
+{
+ LogFlow(("OvlView(%p) vboxReshape:\n", (void *)self));
/*
- * Tell the GL context.
+ * Resize the view.
*/
- //[[self openGLContext] setView:self];
- [[self openGLContext] update];
+ if ([NSThread isMainThread])
+ [self vboxReshapePerform];
+ else
+ {
+ [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
+ vmsvga3dCocoaServiceRunLoop();
- [self vboxClearBuffers];
+ /*
+ * Try update the opengl context.
+ */
+ [[self openGLContext] update];
+ }
- LogFlow(("OvlWin(%p) vboxReshape: returns\n", (void *)self));
+ LogFlow(("OvlView(%p) vboxReshape: returns\n", (void *)self));
}
+/**
+ * This is called when the bounds change.
+ *
+ * We indicate that the FIFO thread must update the GL context.
+ */
+- (void)vboxBoundsDidChange:(NSNotification *)pNotification
+{
+ LogFlow(("OvlView(%p) vboxBoundsDidChange:\n", (void *)self));
+ self->m_fUpdateCtx = true;
+}
+
+/**
+ * This is called when the frame changes size or position.
+ *
+ * We indicate that the FIFO thread must update the GL context.
+ */
+- (void)vboxFrameDidChange:(NSNotification *)pNotification
+{
+ LogFlow(("OvlView(%p) vboxFrameDidChange:\n", (void *)self));
+ self->m_fUpdateCtx = true;
+}
/**
- * Changes to the OpenGL context associated with the view.
- * @returns Previous OpenGL context.
- */
+ * This is called when moved to different screen/GPU or/and when the GL context
+ * needs updating.
+ *
+ * We indicate that the FIFO thread must update the GL context.
+ */
+- (void)vboxFrameDidChangeGlobal:(NSNotification *)pNotification
+{
+ LogFlow(("OvlView(%p) vboxFrameDidChangeGlobal:\n", (void *)self));
+ self->m_fUpdateCtx = true;
+}
+
+/** This enables the vboxFrameDidChange notification. */
+- (BOOL)postsFrameChangedNotifications
+{
+ LogFlow(("OvlView(%p) postsFrameChangedNotifications:\n", (void *)self));
+ return YES;
+}
+
+/**
+ * Removes the view from the parent, if it has one, and makes sure it's hidden.
+ *
+ * This is callbed before destroying it.
+ */
+- (void)vboxRemoveFromSuperviewAndHide
+{
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide:\n", (void *)self));
+ if (m_pParentView)
+ {
+ /*
+ * The removeFromSuperview has been frequently seen to deadlock thing like this:
+ * #0 0x00007fff8db440fa in __psynch_cvwait ()
+ * #1 0x00007fff8d0acfb9 in _pthread_cond_wait ()
+ * #2 0x00007fff8a1bc8f0 in -[NSViewHierarchyLock _lockForWriting:handler:] ()
+ * #3 0x00007fff8a1bc171 in -[NSView removeFromSuperview] ()
+ * #4 0x000000010cffb2bb in -[VMSVGA3DOverlayView vboxRemoveFromSuperviewAndHide] (self=0x10a1da550, _cmd=0x10cffd734) at DevVGA-SVGA3d-cocoa.m:467
+ * #5 0x000000010cffbed3 in vmsvga3dCocoaDestroyViewAndContext (pView=0x10a1da550, pCtx=0x10a1da630) at DevVGA-SVGA3d-cocoa.m:662
+ * (This is from OS X 10.8.5.)
+ */
+ if ([NSThread isMainThread])
+ {
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling removeFromSuperview\n", (void *)self));
+ [self removeFromSuperview];
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling setHidden\n", (void *)self));
+ [self setHidden:YES];
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling setHidden\n", (void *)self));
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ }
+ else
+ {
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: defering to main thread\n", (void *)self));
+ vmsvga3dCocoaServiceRunLoop();
+ [self performSelectorOnMainThread:@selector(vboxRemoveFromSuperviewAndHide) withObject:nil waitUntilDone:YES];
+ vmsvga3dCocoaServiceRunLoop();
+ LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: main thread done\n", (void *)self));
+ }
+ }
+}
+
+
+/**
+ * Changes to the OpenGL context associated with the view.
+ * @returns Previous OpenGL context.
+ */
- (NSOpenGLContext *)makeCurrentGLContext
{
NSOpenGLContext *pSavedCtx = [NSOpenGLContext currentContext];
@@ -358,9 +570,9 @@
/**
- * Restores the previous OpenGL context after
- * makeCurrentGLContext.
- *
+ * Restores the previous OpenGL context after
+ * makeCurrentGLContext.
+ *
* @param pSavedCtx The makeCurrentGLContext return value.
*/
- (void)restoreSavedGLContext:(NSOpenGLContext *)pSavedCtx
@@ -402,9 +614,17 @@
- (NSOpenGLContext *)openGLContext
{
- /* Stupid hack to work around setView failing early. */
+ /* Stupid hacks to work around setView failing early. This can get kind of
+ noisy on some OS versions, so shut it up a little bit. */
+ /** @todo use NSOpenGLView for the non-visible contexts. */
if (m_pCtx && [m_pCtx view] != self)
- [m_pCtx setView:self];
+ {
+ m_cSetViewAttempts++;
+ if ( m_pParentView
+ || m_cSetViewAttempts < 64
+ || (m_cSetViewAttempts & (m_cSetViewAttempts < _64K ? 0xfff : 0x7fff)) == 0 )
+ [m_pCtx setView:self];
+ }
return m_pCtx;
}
@@ -414,10 +634,11 @@
}
#endif /* USE_NSOPENGLVIEW */
-/*
+/*
* Overridden NSOpenGLView / NSView methods:
*/
+/** @todo do we need this? */
-(void)viewDidMoveToWindow
{
LogFlow(("OvlView(%p) viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
@@ -434,7 +655,7 @@
-(void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
{
- LogFlow(("OvlView(%p) resizeWithOldSuperviewSize: %d,%d -> %d,%d\n", (void *)self,
+ LogFlow(("OvlView(%p) resizeWithOldSuperviewSize: %d,%d -> %d,%d\n", (void *)self,
(int)oldBoundsSize.width, (int)oldBoundsSize.height, (int)[self bounds].size.width, (int)[self bounds].size.height));
[super resizeWithOldSuperviewSize:oldBoundsSize];
[self vboxReshape];
@@ -442,11 +663,11 @@
- (void)drawRect:(NSRect)rect
{
- if (m_fClear)
- {
- m_fClear = false;
- [self vboxClearBuffers];
- }
+// if (m_fClear)
+// {
+// m_fClear = false;
+// [self vboxClearBuffers];
+// }
}
@end /* VMSVGA3DOverlayView */
@@ -469,11 +690,17 @@ VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaServiceRunLoop(void)
}
+/**
+ * Document me later.
+ *
+ * @param pParentView The parent view if this is a context we'll be
+ * presenting to.
+ */
VMSVGA3DCOCOA_DECL(bool) vmsvga3dCocoaCreateViewAndContext(NativeNSViewRef *ppView, NativeNSOpenGLContextRef *ppCtx,
NativeNSViewRef pParentView, uint32_t cx, uint32_t cy,
NativeNSOpenGLContextRef pSharedCtx, bool fOtherProfile)
{
- LogFlow(("vmsvga3dCocoaCreateViewAndContext: pParentView=%d size=%d,%d pSharedCtx=%p fOtherProfile=%RTbool\n",
+ LogFlow(("vmsvga3dCocoaCreateViewAndContext: pParentView=%d size=%d,%d pSharedCtx=%p fOtherProfile=%RTbool\n",
(void *)pParentView, cx, cy, (void *)pSharedCtx, fOtherProfile));
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
vmsvga3dCocoaServiceRunLoop();
@@ -512,13 +739,14 @@ VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pVie
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
/* The view */
- [pView removeFromSuperview];
- [pView setHidden: YES];
- Log(("vmsvga3dCocoaDestroyViewAndContext: view %p ref count=%d\n", (void *)pView, [pView retainCount]));
- [pView release];
+ VMSVGA3DOverlayView *pOvlView = (VMSVGA3DOverlayView *)pView;
+ [pOvlView vboxRemoveFromSuperviewAndHide];
+
+ Log(("vmsvga3dCocoaDestroyViewAndContext: view %p ref count=%d\n", (void *)pOvlView, [pOvlView retainCount]));
+ [pOvlView release];
/* The OpenGL context. */
- Log(("vmsvga3dCocoaDestroyViewAndContext: ctx %p ref count=%d\n", (void *)pCtx, [pView retainCount]));
+ Log(("vmsvga3dCocoaDestroyViewAndContext: ctx %p ref count=%d\n", (void *)pCtx, [pCtx retainCount]));
[pCtx release];
[pPool release];
@@ -526,25 +754,113 @@ VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pVie
}
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewInfo(PCDBGFINFOHLP pHlp, NativeNSViewRef pView)
+{
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ if (pView != nil)
+ {
+ VMSVGA3DOverlayView *pOvlView = (VMSVGA3DOverlayView *)pView;
+
+ NSRect FrameRect = [pOvlView frame];
+ pHlp->pfnPrintf(pHlp, " Frame rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
+ FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
+ NSRect BoundsRect = [pOvlView bounds];
+ pHlp->pfnPrintf(pHlp, " Bounds rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(BoundsRect.origin.x), FLOAT_FMT_ARGS(BoundsRect.origin.y),
+ FLOAT_FMT_ARGS(BoundsRect.size.width), FLOAT_FMT_ARGS(BoundsRect.size.height));
+ NSRect VisibleRect = [pOvlView visibleRect];
+ pHlp->pfnPrintf(pHlp, " Visible rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(VisibleRect.origin.x), FLOAT_FMT_ARGS(VisibleRect.origin.y),
+ FLOAT_FMT_ARGS(VisibleRect.size.width), FLOAT_FMT_ARGS(VisibleRect.size.height));
+ pHlp->pfnPrintf(pHlp, " isHidden: %RTbool\n", [pOvlView isHidden] != NO);
+ pHlp->pfnPrintf(pHlp, " canDraw: %RTbool\n", [pOvlView canDraw] != NO);
+ pHlp->pfnPrintf(pHlp, " wantsDefaultClipping: %RTbool\n", [pOvlView wantsDefaultClipping] != NO);
+ pHlp->pfnPrintf(pHlp, " wantsLayer: %RTbool\n", [pOvlView wantsLayer] != NO);
+ if ([pOvlView layer] != nil)
+ pHlp->pfnPrintf(pHlp, " Layer: %p\n", [pOvlView layer] != nil);
+ pHlp->pfnPrintf(pHlp, " isOpaque: %RTbool\n", [pOvlView isOpaque] != NO);
+ pHlp->pfnPrintf(pHlp, " autoresizingMask: %#x\n", [pOvlView autoresizingMask]);
+ pHlp->pfnPrintf(pHlp, " isRotatedOrScaledFromBase: %RTbool\n", [pOvlView isRotatedOrScaledFromBase] != NO);
+
+ NSView *pEnclosingScrollView = [pOvlView enclosingScrollView];
+ NSView *pCurView = [pOvlView superview];
+ uint32_t iLevel;
+ for (iLevel = 1; pCurView && iLevel < 7; iLevel++)
+ {
+ NSView *pNextView = [pCurView superview];
+ pHlp->pfnPrintf(pHlp, " Superview#%u: %p, super=%p\n", iLevel, pCurView, pNextView);
+ FrameRect = [pCurView frame];
+ pHlp->pfnPrintf(pHlp, " Superview#%u frame: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ iLevel,
+ FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
+ FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
+ BoundsRect = [pCurView bounds];
+ pHlp->pfnPrintf(pHlp, " Superview#%u bounds: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ iLevel,
+ FLOAT_FMT_ARGS(BoundsRect.origin.x), FLOAT_FMT_ARGS(BoundsRect.origin.y),
+ FLOAT_FMT_ARGS(BoundsRect.size.width), FLOAT_FMT_ARGS(BoundsRect.size.height));
+ if (pEnclosingScrollView == pCurView)
+ pHlp->pfnPrintf(pHlp, " Superview#%u is enclosing scroll view\n", iLevel);
+ if ([pCurView enclosingScrollView])
+ pHlp->pfnPrintf(pHlp, " Superview#%u has an enclosing scroll view: %p\n", [pCurView enclosingScrollView]);
+ pCurView = pNextView;
+ }
+ if (pCurView)
+ pHlp->pfnPrintf(pHlp, " (There are more super views)\n");
+
+ NSWindow *pWindow = [pOvlView window];
+ if (pWindow != nil)
+ {
+ pHlp->pfnPrintf(pHlp, " Window: %p\n", pWindow);
+ FrameRect = [pWindow frame];
+ pHlp->pfnPrintf(pHlp, " Window frame: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
+ FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
+ CGFloat rFactor = [pWindow backingScaleFactor];
+ pHlp->pfnPrintf(pHlp, " W.backingScaleFactor: " FLOAT_FMT_STR "\n", FLOAT_FMT_ARGS(rFactor));
+ }
+
+ }
+ [pPool release];
+}
+
+
+/** @note Not currently used. */
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
{
LogFlow(("vmsvga3dCocoaViewSetPosition: pView=%p pParentView=%p (%d,%d)\n", (void *)pView, (void *)pParentView, x, y));
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
- [(VMSVGA3DOverlayView *)pView setPos:NSMakePoint(x, y)];
+ [(VMSVGA3DOverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
[pPool release];
LogFlow(("vmsvga3dCocoaViewSetPosition: returns\n"));
}
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewUpdateViewport(NativeNSViewRef pView)
+{
+ LogFlow(("vmsvga3dCocoaViewSetSize: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
+
+ /* Possible that we don't actually need to do this (i.e. this API), but right now I'm
+ leaving it to be sure things actually work right when scrolling. */
+ [pOverlayView vboxScheduleCtxUpdate];
+
+ [pPool release];
+ LogFlow(("vmsvga3dCocoaViewSetSize: returns\n"));
+}
+
+
VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
{
LogFlow(("vmsvga3dCocoaViewSetSize: pView=%p (%d,%d)\n", (void *)pView, cx, cy));
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
- [pOverlayView setSize:NSMakeSize(cx, cy)];
+ [pOverlayView vboxSetSize:NSMakeSize(cx, cy)];
[pPool release];
LogFlow(("vmsvga3dCocoaViewSetSize: returns\n"));
@@ -553,7 +869,7 @@ VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int cx,
void vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
{
- LogFlow(("vmsvga3dCocoaViewSetSize: pView=%p, pCtx=%p\n", (void*)pView, (void*)pCtx));
+ LogFlow(("vmsvga3dCocoaViewMakeCurrentContext: pView=%p, pCtx=%p\n", (void*)pView, (void*)pCtx));
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
@@ -568,12 +884,13 @@ void vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLCo
sideeffect of the openGLContext method call. (hack alert!) */
AssertRelease([pOverlayView openGLContext] == pCtx);
[pCtx makeCurrentContext];
+ [pOverlayView vboxUpdateCtxIfNecessary];
}
else
- [NSOpenGLContext clearCurrentContext];
+ [NSOpenGLContext clearCurrentContext];
[pPool release];
- LogFlow(("vmsvga3dCocoaSwapBuffers: returns\n"));
+ LogFlow(("vmsvga3dCocoaViewMakeCurrentContext: returns\n"));
}
@@ -581,14 +898,12 @@ void vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pC
{
LogFlow(("vmsvga3dCocoaSwapBuffers: pView=%p, pCtx=%p\n", (void*)pView, (void*)pCtx));
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ VMSVGA3DOverlayView *pMyView = (VMSVGA3DOverlayView *)pView;
#ifndef USE_NSOPENGLVIEW
/* Hack alert! setView fails early on so call openGLContext to try again. */
- VMSVGA3DOverlayView *pMyView = (VMSVGA3DOverlayView *)pView;
if ([pCtx view] == NULL)
[pMyView openGLContext];
-#elif defined(RT_STRICT)
- NSOpenGLView *pMyView = (NSOpenGLView *)pView;
#endif
Assert(pCtx == [NSOpenGLContext currentContext]);
@@ -598,7 +913,11 @@ void vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pC
[pCtx flushBuffer];
//[pView setNeedsDisplay:YES];
vmsvga3dCocoaServiceRunLoop();
-
+
+ /* If buffer clearing or/and context updates are pending, execute that now. */
+ [pMyView vboxUpdateCtxIfNecessary];
+ [pMyView vboxClearBackBufferIfNecessary];
+
[pPool release];
LogFlow(("vmsvga3dCocoaSwapBuffers: returns\n"));
}
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-info.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-info.cpp
new file mode 100644
index 0000000..c414584
--- /dev/null
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-info.cpp
@@ -0,0 +1,1953 @@
+/* $Id: DevVGA-SVGA3d-info.cpp $ */
+/** @file
+ * DevSVGA3d - VMWare SVGA device, 3D parts - Introspection and debugging.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+
+#include <VBox/vmm/pgm.h> /* required by DevVGA.h */
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
+
+/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
+#include "DevVGA.h"
+
+#include "DevVGA-SVGA.h"
+#include "DevVGA-SVGA3d.h"
+#define VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+#include "DevVGA-SVGA3d-internal.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** Enum value to string mappings for SVGA3dSurfaceFormat, prefix "SVGA3D_". */
+static const VMSVGAINFOENUM g_aSVGA3dSurfaceFormats[] =
+{
+ { SVGA3D_FORMAT_INVALID , "FORMAT_INVALID" },
+ { SVGA3D_X8R8G8B8 , "X8R8G8B8" },
+ { SVGA3D_A8R8G8B8 , "A8R8G8B8" },
+ { SVGA3D_R5G6B5 , "R5G6B5" },
+ { SVGA3D_X1R5G5B5 , "X1R5G5B5" },
+ { SVGA3D_A1R5G5B5 , "A1R5G5B5" },
+ { SVGA3D_A4R4G4B4 , "A4R4G4B4" },
+ { SVGA3D_Z_D32 , "Z_D32" },
+ { SVGA3D_Z_D16 , "Z_D16" },
+ { SVGA3D_Z_D24S8 , "Z_D24S8" },
+ { SVGA3D_Z_D15S1 , "Z_D15S1" },
+ { SVGA3D_LUMINANCE8 , "LUMINANCE8" },
+ { SVGA3D_LUMINANCE4_ALPHA4 , "LUMINANCE4_ALPHA4" },
+ { SVGA3D_LUMINANCE16 , "LUMINANCE16" },
+ { SVGA3D_LUMINANCE8_ALPHA8 , "LUMINANCE8_ALPHA8" },
+ { SVGA3D_DXT1 , "DXT1" },
+ { SVGA3D_DXT2 , "DXT2" },
+ { SVGA3D_DXT3 , "DXT3" },
+ { SVGA3D_DXT4 , "DXT4" },
+ { SVGA3D_DXT5 , "DXT5" },
+ { SVGA3D_BUMPU8V8 , "BUMPU8V8" },
+ { SVGA3D_BUMPL6V5U5 , "BUMPL6V5U5" },
+ { SVGA3D_BUMPX8L8V8U8 , "BUMPX8L8V8U8" },
+ { SVGA3D_BUMPL8V8U8 , "BUMPL8V8U8" },
+ { SVGA3D_ARGB_S10E5 , "ARGB_S10E5" },
+ { SVGA3D_ARGB_S23E8 , "ARGB_S23E8" },
+ { SVGA3D_A2R10G10B10 , "A2R10G10B10" },
+ { SVGA3D_V8U8 , "V8U8" },
+ { SVGA3D_Q8W8V8U8 , "Q8W8V8U8" },
+ { SVGA3D_CxV8U8 , "CxV8U8" },
+ { SVGA3D_X8L8V8U8 , "X8L8V8U8" },
+ { SVGA3D_A2W10V10U10 , "A2W10V10U10" },
+ { SVGA3D_ALPHA8 , "ALPHA8" },
+ { SVGA3D_R_S10E5 , "R_S10E5" },
+ { SVGA3D_R_S23E8 , "R_S23E8" },
+ { SVGA3D_RG_S10E5 , "RG_S10E5" },
+ { SVGA3D_RG_S23E8 , "RG_S23E8" },
+ { SVGA3D_BUFFER , "BUFFER" },
+ { SVGA3D_Z_D24X8 , "Z_D24X8" },
+ { SVGA3D_V16U16 , "V16U16" },
+ { SVGA3D_G16R16 , "G16R16" },
+ { SVGA3D_A16B16G16R16 , "A16B16G16R16" },
+ { SVGA3D_UYVY , "UYVY" },
+ { SVGA3D_YUY2 , "YUY2" },
+ { SVGA3D_NV12 , "NV12" },
+ { SVGA3D_AYUV , "AYUV" },
+ { SVGA3D_BC4_UNORM , "BC4_UNORM" },
+ { SVGA3D_BC5_UNORM , "BC5_UNORM" },
+ { SVGA3D_Z_DF16 , "Z_DF16" },
+ { SVGA3D_Z_DF24 , "Z_DF24" },
+ { SVGA3D_Z_D24S8_INT , "Z_D24S8_INT" },
+};
+VMSVGAINFOENUMMAP_MAKE(RT_NOTHING, g_SVGA3dSurfaceFormat2String, g_aSVGA3dSurfaceFormats, "SVGA3D_");
+
+/** Values for SVGA3dTextureFilter, prefix SVGA3D_TEX_FILTER_. */
+static const char * const g_apszTexureFilters[] =
+{
+ "NONE",
+ "NEAREST",
+ "LINEAR",
+ "ANISOTROPIC",
+ "FLATCUBIC",
+ "GAUSSIANCUBIC",
+ "PYRAMIDALQUAD",
+ "GAUSSIANQUAD",
+};
+
+/** SVGA3dSurfaceFlags values, prefix SVGA3D_SURFACE_. */
+static VMSVGAINFOFLAGS32 const g_aSvga3DSurfaceFlags[] =
+{
+ { SVGA3D_SURFACE_CUBEMAP , "CUBEMAP" },
+ { SVGA3D_SURFACE_HINT_STATIC , "HINT_STATIC" },
+ { SVGA3D_SURFACE_HINT_DYNAMIC , "HINT_DYNAMIC" },
+ { SVGA3D_SURFACE_HINT_INDEXBUFFER , "HINT_INDEXBUFFER" },
+ { SVGA3D_SURFACE_HINT_VERTEXBUFFER , "HINT_VERTEXBUFFER" },
+ { SVGA3D_SURFACE_HINT_TEXTURE , "HINT_TEXTURE" },
+ { SVGA3D_SURFACE_HINT_RENDERTARGET , "HINT_RENDERTARGET" },
+ { SVGA3D_SURFACE_HINT_DEPTHSTENCIL , "HINT_DEPTHSTENCIL" },
+ { SVGA3D_SURFACE_HINT_WRITEONLY , "HINT_WRITEONLY" },
+ { SVGA3D_SURFACE_MASKABLE_ANTIALIAS , "MASKABLE_ANTIALIAS" },
+ { SVGA3D_SURFACE_AUTOGENMIPMAPS , "AUTOGENMIPMAPS" },
+};
+
+
+#ifdef VMSVGA3D_DIRECT3D
+
+/** Values for D3DFORMAT, prefix D3DFMT_. */
+static VMSVGAINFOENUM const g_aD3DFormats[] =
+{
+ { D3DFMT_UNKNOWN , "UNKNOWN" },
+ { D3DFMT_R8G8B8 , "R8G8B8" },
+ { D3DFMT_A8R8G8B8 , "A8R8G8B8" },
+ { D3DFMT_X8R8G8B8 , "X8R8G8B8" },
+ { D3DFMT_R5G6B5 , "R5G6B5" },
+ { D3DFMT_X1R5G5B5 , "X1R5G5B5" },
+ { D3DFMT_A1R5G5B5 , "A1R5G5B5" },
+ { D3DFMT_A4R4G4B4 , "A4R4G4B4" },
+ { D3DFMT_R3G3B2 , "R3G3B2" },
+ { D3DFMT_A8 , "A8" },
+ { D3DFMT_A8R3G3B2 , "A8R3G3B2" },
+ { D3DFMT_X4R4G4B4 , "X4R4G4B4" },
+ { D3DFMT_A2B10G10R10 , "A2B10G10R10" },
+ { D3DFMT_A8B8G8R8 , "A8B8G8R8" },
+ { D3DFMT_X8B8G8R8 , "X8B8G8R8" },
+ { D3DFMT_G16R16 , "G16R16" },
+ { D3DFMT_A2R10G10B10 , "A2R10G10B10" },
+ { D3DFMT_A16B16G16R16 , "A16B16G16R16" },
+ { D3DFMT_A8P8 , "A8P8" },
+ { D3DFMT_P8 , "P8" },
+ { D3DFMT_L8 , "L8" },
+ { D3DFMT_A8L8 , "A8L8" },
+ { D3DFMT_A4L4 , "A4L4" },
+ { D3DFMT_V8U8 , "V8U8" },
+ { D3DFMT_L6V5U5 , "L6V5U5" },
+ { D3DFMT_X8L8V8U8 , "X8L8V8U8" },
+ { D3DFMT_Q8W8V8U8 , "Q8W8V8U8" },
+ { D3DFMT_V16U16 , "V16U16" },
+ { D3DFMT_A2W10V10U10 , "A2W10V10U10" },
+ { D3DFMT_D16_LOCKABLE , "D16_LOCKABLE" },
+ { D3DFMT_D32 , "D32" },
+ { D3DFMT_D15S1 , "D15S1" },
+ { D3DFMT_D24S8 , "D24S8" },
+ { D3DFMT_D24X8 , "D24X8" },
+ { D3DFMT_D24X4S4 , "D24X4S4" },
+ { D3DFMT_D16 , "D16" },
+ { D3DFMT_L16 , "L16" },
+ { D3DFMT_D32F_LOCKABLE , "D32F_LOCKABLE" },
+ { D3DFMT_D24FS8 , "D24FS8" },
+ { D3DFMT_VERTEXDATA , "VERTEXDATA" },
+ { D3DFMT_INDEX16 , "INDEX16" },
+ { D3DFMT_INDEX32 , "INDEX32" },
+ { D3DFMT_Q16W16V16U16 , "Q16W16V16U16" },
+ { D3DFMT_R16F , "R16F" },
+ { D3DFMT_G16R16F , "G16R16F" },
+ { D3DFMT_A16B16G16R16F , "A16B16G16R16F" },
+ { D3DFMT_R32F , "R32F" },
+ { D3DFMT_G32R32F , "G32R32F" },
+ { D3DFMT_A32B32G32R32F , "A32B32G32R32F" },
+ { D3DFMT_CxV8U8 , "CxV8U8" },
+ /* Fourcc values, MSB is in the right most char: */
+ { D3DFMT_MULTI2_ARGB8 , "MULTI2_ARGB8" },
+ { D3DFMT_DXT1 , "DXT1" },
+ { D3DFMT_DXT2 , "DXT2" },
+ { D3DFMT_YUY2 , "YUY2" },
+ { D3DFMT_DXT3 , "DXT3" },
+ { D3DFMT_DXT4 , "DXT4" },
+ { D3DFMT_DXT5 , "DXT5" },
+ { D3DFMT_G8R8_G8B8 , "G8R8_G8B8" },
+ { D3DFMT_R8G8_B8G8 , "R8G8_B8G8" },
+ { D3DFMT_UYVY , "UYVY" },
+ { D3DFMT_FORCE_DWORD , "FORCE_DWORD" }, /* UINT32_MAX */
+};
+VMSVGAINFOENUMMAP_MAKE(static, g_D3DFormat2String, g_aD3DFormats, "D3DFMT_");
+
+/** Values for D3DMULTISAMPLE_TYPE, prefix D3DMULTISAMPLE_. */
+static VMSVGAINFOENUM const g_aD3DMultiSampleTypes[] =
+{
+ { D3DMULTISAMPLE_NONE , "NONE" },
+ { D3DMULTISAMPLE_NONMASKABLE , "NONMASKABLE" },
+ { D3DMULTISAMPLE_2_SAMPLES , "2_SAMPLES" },
+ { D3DMULTISAMPLE_3_SAMPLES , "3_SAMPLES" },
+ { D3DMULTISAMPLE_4_SAMPLES , "4_SAMPLES" },
+ { D3DMULTISAMPLE_5_SAMPLES , "5_SAMPLES" },
+ { D3DMULTISAMPLE_6_SAMPLES , "6_SAMPLES" },
+ { D3DMULTISAMPLE_7_SAMPLES , "7_SAMPLES" },
+ { D3DMULTISAMPLE_8_SAMPLES , "8_SAMPLES" },
+ { D3DMULTISAMPLE_9_SAMPLES , "9_SAMPLES" },
+ { D3DMULTISAMPLE_10_SAMPLES , "10_SAMPLES" },
+ { D3DMULTISAMPLE_11_SAMPLES , "11_SAMPLES" },
+ { D3DMULTISAMPLE_12_SAMPLES , "12_SAMPLES" },
+ { D3DMULTISAMPLE_13_SAMPLES , "13_SAMPLES" },
+ { D3DMULTISAMPLE_14_SAMPLES , "14_SAMPLES" },
+ { D3DMULTISAMPLE_15_SAMPLES , "15_SAMPLES" },
+ { D3DMULTISAMPLE_16_SAMPLES , "16_SAMPLES" },
+ { D3DMULTISAMPLE_FORCE_DWORD , "FORCE_DWORD" },
+};
+VMSVGAINFOENUMMAP_MAKE(static, g_D3DMultiSampleType2String, g_aD3DMultiSampleTypes, "D3DMULTISAMPLE_");
+
+/** D3DUSAGE_XXX flag value, prefix D3DUSAGE_. */
+static VMSVGAINFOFLAGS32 const g_aD3DUsageFlags[] =
+{
+ { D3DUSAGE_RENDERTARGET , "RENDERTARGET" },
+ { D3DUSAGE_DEPTHSTENCIL , "DEPTHSTENCIL" },
+ { D3DUSAGE_WRITEONLY , "WRITEONLY" },
+ { D3DUSAGE_SOFTWAREPROCESSING , "SOFTWAREPROCESSING" },
+ { D3DUSAGE_DONOTCLIP , "DONOTCLIP" },
+ { D3DUSAGE_POINTS , "POINTS" },
+ { D3DUSAGE_RTPATCHES , "RTPATCHES" },
+ { D3DUSAGE_NPATCHES , "NPATCHES" },
+ { D3DUSAGE_DYNAMIC , "DYNAMIC" },
+ { D3DUSAGE_AUTOGENMIPMAP , "AUTOGENMIPMAP" },
+ { D3DUSAGE_RESTRICTED_CONTENT , "RESTRICTED_CONTENT" },
+ { D3DUSAGE_RESTRICT_SHARED_RESOURCE_DRIVER , "RESTRICT_SHARED_RESOURCE_DRIVER" },
+ { D3DUSAGE_RESTRICT_SHARED_RESOURCE , "RESTRICT_SHARED_RESOURCE" },
+ { D3DUSAGE_DMAP , "DMAP" },
+ { D3DUSAGE_NONSECURE , "NONSECURE" },
+ { D3DUSAGE_TEXTAPI , "TEXTAPI" },
+};
+
+#endif /* VMSVGA3D_DIRECT3D */
+
+
+/**
+ * Worker for vmsvga3dUpdateHeapBuffersForSurfaces.
+ *
+ * This will allocate heap buffers if necessary, thus increasing the memory
+ * usage of the process.
+ *
+ * @todo Would be interesting to share this code with the saved state code.
+ *
+ * @returns VBox status code.
+ * @param pState The 3D state structure.
+ * @param pSurface The surface to refresh the heap buffers for.
+ */
+static int vmsvga3dSurfaceUpdateHeapBuffers(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface)
+{
+ /*
+ * Currently we've got trouble retreving bit for DEPTHSTENCIL
+ * surfaces both for OpenGL and D3D, so skip these here (don't
+ * wast memory on them).
+ */
+ uint32_t const fSwitchFlags = pSurface->flags
+ & ( SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER
+ | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET
+ | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP);
+ if ( fSwitchFlags != SVGA3D_SURFACE_HINT_DEPTHSTENCIL
+ && fSwitchFlags != (SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_HINT_TEXTURE))
+ {
+
+#ifdef VMSVGA3D_OPENGL
+ /*
+ * Change OpenGL context to the one the surface is associated with.
+ */
+ PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
+#endif
+
+ /*
+ * Work thru each mipmap level for each face.
+ */
+ for (uint32_t iFace = 0; iFace < pSurface->cFaces; iFace++)
+ {
+ Assert(pSurface->faces[iFace].numMipLevels <= pSurface->faces[0].numMipLevels);
+ PVMSVGA3DMIPMAPLEVEL pMipmapLevel = &pSurface->pMipmapLevels[iFace * pSurface->faces[0].numMipLevels];
+ for (uint32_t i = 0; i < pSurface->faces[iFace].numMipLevels; i++, pMipmapLevel++)
+ {
+#ifdef VMSVGA3D_DIRECT3D
+ if (pSurface->u.pSurface)
+#else
+ if (pSurface->oglId.texture != OPENGL_INVALID_ID)
+#endif
+ {
+ Assert(pMipmapLevel->cbSurface);
+ Assert(pMipmapLevel->cbSurface == pMipmapLevel->cbSurfacePitch * pMipmapLevel->size.height); /* correct for depth stuff? */
+
+ /*
+ * Make sure we've got surface memory buffer.
+ */
+ uint8_t *pbDst = (uint8_t *)pMipmapLevel->pSurfaceData;
+ if (!pbDst)
+ {
+ pMipmapLevel->pSurfaceData = pbDst = (uint8_t *)RTMemAllocZ(pMipmapLevel->cbSurface);
+ AssertReturn(pbDst, VERR_NO_MEMORY);
+ }
+
+#ifdef VMSVGA3D_DIRECT3D
+ /*
+ * D3D specifics.
+ */
+ HRESULT hr;
+ switch (fSwitchFlags)
+ {
+ case SVGA3D_SURFACE_HINT_TEXTURE:
+ case SVGA3D_SURFACE_HINT_RENDERTARGET:
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ {
+ /*
+ * Lock the buffer and make it accessible to memcpy.
+ */
+ D3DLOCKED_RECT LockedRect;
+ if (fSwitchFlags & SVGA3D_SURFACE_HINT_TEXTURE)
+ {
+ if (pSurface->bounce.pTexture)
+ {
+ if ( !pSurface->fDirty
+ && fSwitchFlags == (SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET)
+ && i == 0 /* only the first time */)
+ {
+ /** @todo stricter checks for associated context */
+ uint32_t cid = pSurface->idAssociatedContext;
+ if ( cid >= pState->cContexts
+ || pState->papContexts[cid]->id != cid)
+ {
+ Log(("vmsvga3dSurfaceUpdateHeapBuffers: invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ }
+ PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+
+ IDirect3DSurface9 *pDst = NULL;
+ hr = pSurface->bounce.pTexture->GetSurfaceLevel(i, &pDst);
+ AssertMsgReturn(hr == D3D_OK, ("GetSurfaceLevel failed with %#x\n", hr), VERR_INTERNAL_ERROR);
+
+ IDirect3DSurface9 *pSrc = NULL;
+ hr = pSurface->u.pTexture->GetSurfaceLevel(i, &pSrc);
+ AssertMsgReturn(hr == D3D_OK, ("GetSurfaceLevel failed with %#x\n", hr), VERR_INTERNAL_ERROR);
+
+ hr = pContext->pDevice->GetRenderTargetData(pSrc, pDst);
+ AssertMsgReturn(hr == D3D_OK, ("GetRenderTargetData failed with %#x\n", hr), VERR_INTERNAL_ERROR);
+
+ pSrc->Release();
+ pDst->Release();
+ }
+
+ hr = pSurface->bounce.pTexture->LockRect(i, /* texture level */
+ &LockedRect,
+ NULL,
+ D3DLOCK_READONLY);
+ }
+ else
+ hr = pSurface->u.pTexture->LockRect(i, /* texture level */
+ &LockedRect,
+ NULL,
+ D3DLOCK_READONLY);
+ }
+ else
+ hr = pSurface->u.pSurface->LockRect(&LockedRect,
+ NULL,
+ D3DLOCK_READONLY);
+ AssertMsgReturn(hr == D3D_OK, ("LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
+
+ /*
+ * Copy the data. Take care in case the pitch differs.
+ */
+ if (pMipmapLevel->cbSurfacePitch == (uint32_t)LockedRect.Pitch)
+ memcpy(pbDst, LockedRect.pBits, pMipmapLevel->cbSurface);
+ else
+ for (uint32_t j = 0; j < pMipmapLevel->size.height; j++)
+ memcpy(pbDst + j * pMipmapLevel->cbSurfacePitch,
+ (uint8_t *)LockedRect.pBits + j * LockedRect.Pitch,
+ pMipmapLevel->cbSurfacePitch);
+
+ /*
+ * Release the buffer.
+ */
+ if (fSwitchFlags & SVGA3D_SURFACE_HINT_TEXTURE)
+ {
+ if (pSurface->bounce.pTexture)
+ {
+ hr = pSurface->bounce.pTexture->UnlockRect(i);
+ AssertMsgReturn(hr == D3D_OK, ("UnlockRect failed with %#x\n", hr), VERR_INTERNAL_ERROR);
+ }
+ else
+ hr = pSurface->u.pTexture->UnlockRect(i);
+ }
+ else
+ hr = pSurface->u.pSurface->UnlockRect();
+ AssertMsgReturn(hr == D3D_OK, ("UnlockRect failed with %#x\n", hr), VERR_INTERNAL_ERROR);
+ break;
+ }
+
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ {
+ void *pvD3DData = NULL;
+ hr = pSurface->u.pVertexBuffer->Lock(0, 0, &pvD3DData, D3DLOCK_READONLY);
+ AssertMsgReturn(hr == D3D_OK, ("Lock vertex failed with %x\n", hr), VERR_INTERNAL_ERROR);
+
+ memcpy(pbDst, pvD3DData, pMipmapLevel->cbSurface);
+
+ hr = pSurface->u.pVertexBuffer->Unlock();
+ AssertMsg(hr == D3D_OK, ("Unlock vertex failed with %x\n", hr));
+ break;
+ }
+
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ {
+ void *pvD3DData = NULL;
+ hr = pSurface->u.pIndexBuffer->Lock(0, 0, &pvD3DData, D3DLOCK_READONLY);
+ AssertMsgReturn(hr == D3D_OK, ("Lock index failed with %x\n", hr), VERR_INTERNAL_ERROR);
+
+ memcpy(pbDst, pvD3DData, pMipmapLevel->cbSurface);
+
+ hr = pSurface->u.pIndexBuffer->Unlock();
+ AssertMsg(hr == D3D_OK, ("Unlock index failed with %x\n", hr));
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("%#x\n", fSwitchFlags));
+ }
+
+#elif defined(VMSVGA3D_OPENGL)
+ /*
+ * OpenGL specifics.
+ */
+ switch (fSwitchFlags)
+ {
+ case SVGA3D_SURFACE_HINT_TEXTURE:
+ case SVGA3D_SURFACE_HINT_RENDERTARGET:
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ {
+ GLint activeTexture;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+
+ glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+
+ /* Set row length and alignment of the output data. */
+ VMSVGAPACKPARAMS SavedParams;
+ vmsvga3dOglSetPackParams(pState, pContext, pSurface, &SavedParams);
+
+ glGetTexImage(GL_TEXTURE_2D,
+ i,
+ pSurface->formatGL,
+ pSurface->typeGL,
+ pbDst);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+
+ vmsvga3dOglRestorePackParams(pState, pContext, pSurface, &SavedParams);
+
+ /* Restore the old active texture. */
+ glBindTexture(GL_TEXTURE_2D, activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ break;
+ }
+
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ {
+ pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pSurface->oglId.buffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+
+ void *pvSrc = pState->ext.glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ if (RT_VALID_PTR(pvSrc))
+ memcpy(pbDst, pvSrc, pMipmapLevel->cbSurface);
+ else
+ AssertPtr(pvSrc);
+
+ pState->ext.glUnmapBuffer(GL_ARRAY_BUFFER);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+
+ pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ break;
+ }
+
+ default:
+ AssertMsgFailed(("%#x\n", fSwitchFlags));
+ }
+#else
+# error "misconfigured"
+#endif
+ }
+ /* else: There is no data in hardware yet, so whatever we got is already current. */
+ }
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Updates the heap buffers for all surfaces or one specific one.
+ *
+ * @param pThis The VGA device instance data.
+ * @param sid The surface ID, UINT32_MAX if all.
+ * @thread VMSVGAFIFO
+ */
+void vmsvga3dUpdateHeapBuffersForSurfaces(PVGASTATE pThis, uint32_t sid)
+{
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturnVoid(pState);
+
+ if (sid == UINT32_MAX)
+ {
+ uint32_t cSurfaces = pState->cSurfaces;
+ for (sid = 0; sid < cSurfaces; sid++)
+ {
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ if (pSurface && pSurface->id == sid)
+ vmsvga3dSurfaceUpdateHeapBuffers(pState, pSurface);
+ }
+ }
+ else if (sid < pState->cSurfaces)
+ {
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ if (pSurface && pSurface->id == sid)
+ vmsvga3dSurfaceUpdateHeapBuffers(pState, pSurface);
+ }
+}
+
+
+
+
+void vmsvga3dInfoU32Flags(PCDBGFINFOHLP pHlp, uint32_t fFlags, const char *pszPrefix, PCVMSVGAINFOFLAGS32 paFlags, uint32_t cFlags)
+{
+ for (uint32_t i = 0; i < cFlags; i++)
+ if ((paFlags[i].fFlags & fFlags) == paFlags[i].fFlags)
+ {
+ Assert(paFlags[i].fFlags);
+ pHlp->pfnPrintf(pHlp, " %s%s", pszPrefix, paFlags[i].pszJohnny);
+ fFlags &= ~paFlags[i].fFlags;
+ if (!fFlags)
+ return;
+ }
+ if (fFlags)
+ pHlp->pfnPrintf(pHlp, " UNKNOWN_%#x", fFlags);
+}
+
+
+/**
+ * Worker for vmsvgaR3Info that display details of a host window.
+ *
+ * @param pHlp The output methods.
+ * @param idHostWindow The host window handle/id/whatever.
+ */
+void vmsvga3dInfoHostWindow(PCDBGFINFOHLP pHlp, uint64_t idHostWindow)
+{
+#ifdef RT_OS_WINDOWS
+ HWND hwnd = (HWND)(uintptr_t)idHostWindow;
+ Assert((uintptr_t)hwnd == idHostWindow);
+ if (hwnd != NULL)
+ {
+ WINDOWINFO Info;
+ RT_ZERO(Info);
+ Info.cbSize = sizeof(Info);
+ if (GetWindowInfo(hwnd, &Info))
+ {
+ pHlp->pfnPrintf(pHlp, " Window rect: xLeft=%d, yTop=%d, xRight=%d, yBottom=%d (cx=%d, cy=%d)\n",
+ Info.rcWindow.left, Info.rcWindow.top, Info.rcWindow.right, Info.rcWindow.bottom,
+ Info.rcWindow.right - Info.rcWindow.left, Info.rcWindow.bottom - Info.rcWindow.top);
+ pHlp->pfnPrintf(pHlp, " Client rect: xLeft=%d, yTop=%d, xRight=%d, yBottom=%d (cx=%d, cy=%d)\n",
+ Info.rcClient.left, Info.rcClient.top, Info.rcClient.right, Info.rcClient.bottom,
+ Info.rcClient.right - Info.rcClient.left, Info.rcClient.bottom - Info.rcClient.top);
+ pHlp->pfnPrintf(pHlp, " Style: %#x", Info.dwStyle);
+ static const VMSVGAINFOFLAGS32 g_aStyles[] =
+ {
+ { WS_POPUP , "POPUP" },
+ { WS_CHILD , "CHILD" },
+ { WS_MINIMIZE , "MINIMIZE" },
+ { WS_VISIBLE , "VISIBLE" },
+ { WS_DISABLED , "DISABLED" },
+ { WS_CLIPSIBLINGS , "CLIPSIBLINGS" },
+ { WS_CLIPCHILDREN , "CLIPCHILDREN" },
+ { WS_MAXIMIZE , "MAXIMIZE" },
+ { WS_BORDER , "BORDER" },
+ { WS_DLGFRAME , "DLGFRAME" },
+ { WS_VSCROLL , "VSCROLL" },
+ { WS_HSCROLL , "HSCROLL" },
+ { WS_SYSMENU , "SYSMENU" },
+ { WS_THICKFRAME , "THICKFRAME" },
+ { WS_GROUP , "GROUP" },
+ { WS_TABSTOP , "TABSTOP" },
+ };
+ vmsvga3dInfoU32Flags(pHlp, Info.dwStyle, "", g_aStyles, RT_ELEMENTS(g_aStyles));
+ pHlp->pfnPrintf(pHlp, "\n");
+
+ pHlp->pfnPrintf(pHlp, " ExStyle: %#x", Info.dwExStyle);
+ static const VMSVGAINFOFLAGS32 g_aExStyles[] =
+ {
+ { WS_EX_DLGMODALFRAME, "DLGMODALFRAME" },
+ { 0x00000002, "DRAGDETECT" },
+ { WS_EX_NOPARENTNOTIFY, "NOPARENTNOTIFY" },
+ { WS_EX_TOPMOST, "TOPMOST" },
+ { WS_EX_ACCEPTFILES, "ACCEPTFILES" },
+ { WS_EX_TRANSPARENT, "TRANSPARENT" },
+ { WS_EX_MDICHILD, "MDICHILD" },
+ { WS_EX_TOOLWINDOW, "TOOLWINDOW" },
+ { WS_EX_WINDOWEDGE, "WINDOWEDGE" },
+ { WS_EX_CLIENTEDGE, "CLIENTEDGE" },
+ { WS_EX_CONTEXTHELP, "CONTEXTHELP" },
+ { WS_EX_RIGHT, "RIGHT" },
+ /*{ WS_EX_LEFT, "LEFT" }, = 0 */
+ { WS_EX_RTLREADING, "RTLREADING" },
+ /*{ WS_EX_LTRREADING, "LTRREADING" }, = 0 */
+ { WS_EX_LEFTSCROLLBAR, "LEFTSCROLLBAR" },
+ /*{ WS_EX_RIGHTSCROLLBAR, "RIGHTSCROLLBAR" }, = 0 */
+ { WS_EX_CONTROLPARENT, "CONTROLPARENT" },
+ { WS_EX_STATICEDGE, "STATICEDGE" },
+ { WS_EX_APPWINDOW, "APPWINDOW" },
+ { WS_EX_LAYERED, "LAYERED" },
+ { WS_EX_NOINHERITLAYOUT, "NOINHERITLAYOUT" },
+ { WS_EX_LAYOUTRTL, "LAYOUTRTL" },
+ { WS_EX_COMPOSITED, "COMPOSITED" },
+ { WS_EX_NOACTIVATE, "NOACTIVATE" },
+ };
+ vmsvga3dInfoU32Flags(pHlp, Info.dwExStyle, "", g_aExStyles, RT_ELEMENTS(g_aExStyles));
+ pHlp->pfnPrintf(pHlp, "\n");
+
+ pHlp->pfnPrintf(pHlp, " Window Status: %#x\n", Info.dwWindowStatus);
+ if (Info.cxWindowBorders || Info.cyWindowBorders)
+ pHlp->pfnPrintf(pHlp, " Borders: cx=%u, cy=%u\n", Info.cxWindowBorders, Info.cyWindowBorders);
+ pHlp->pfnPrintf(pHlp, " Window Type: %#x\n", Info.atomWindowType);
+ pHlp->pfnPrintf(pHlp, " Creator Ver: %#x\n", Info.wCreatorVersion);
+ }
+ else
+ pHlp->pfnPrintf(pHlp, " GetWindowInfo: last error %d\n", GetLastError());
+ }
+
+#elif defined(RT_OS_DARWIN)
+ int rc = ExplicitlyLoadVBoxSVGA3DObjC(false /*fResolveAllImports*/, NULL /*pErrInfo*/);
+ if (RT_SUCCESS(rc))
+ vmsvga3dCocoaViewInfo(pHlp, (NativeNSViewRef)(uintptr_t)idHostWindow);
+ else
+ pHlp->pfnPrintf(pHlp, " Windows info: vmsvga3dCocoaViewInfo failed to load (%Rrc)\n", rc);
+
+#else
+ pHlp->pfnPrintf(pHlp, " Windows info: Not implemented on this platform\n");
+#endif
+}
+
+
+/**
+ * Looks up an enum value in a translation table.
+ *
+ * @returns The value name.
+ * @param iValue The value to name.
+ * @param pEnumMap Enum value to string mapping.
+ */
+const char *vmsvgaLookupEnum(int32_t iValue, PCVMSVGAINFOENUMMAP pEnumMap)
+{
+ PCVMSVGAINFOENUM paValues = pEnumMap->paValues;
+
+#ifdef VBOX_STRICT
+ /*
+ * Check that it's really sorted, or the binary lookup won't work right.
+ */
+ if (!*pEnumMap->pfAsserted)
+ {
+ *pEnumMap->pfAsserted = true;
+ for (uint32_t i = 1; i < pEnumMap->cValues; i++)
+ Assert(paValues[i - 1].iValue <= paValues[i].iValue);
+ }
+#endif
+
+ /*
+ * Binary search
+ */
+ uint32_t iStart = 0;
+ uint32_t iEnd = (uint32_t)pEnumMap->cValues;
+ for (;;)
+ {
+ uint32_t i = iStart + (iEnd - iStart) / 2;
+ if (iValue < paValues[i].iValue)
+ {
+ if (i > iStart)
+ iEnd = i;
+ else
+ break;
+ }
+ else if (iValue > paValues[i].iValue)
+ {
+ i++;
+ if (i < iEnd)
+ iStart = i;
+ else
+ break;
+ }
+ else
+ return paValues[i].pszName;
+ }
+ return NULL;
+}
+
+
+/**
+ * Formats an enum value as a string, sparse mapping table.
+ *
+ * @returns pszBuffer.
+ * @param pszBuffer The output buffer.
+ * @param cbBuffer The size of the output buffer.
+ * @param pszName The variable name, optional.
+ * @param iValue The enum value.
+ * @param fPrefix Whether to prepend the prefix or not.
+ * @param pEnumMap Enum value to string mapping.
+ */
+char *vmsvgaFormatEnumValueEx(char *pszBuffer, size_t cbBuffer, const char *pszName, int32_t iValue,
+ bool fPrefix, PCVMSVGAINFOENUMMAP pEnumMap)
+{
+ const char *pszValueName = vmsvgaLookupEnum(iValue, pEnumMap);
+ const char *pszPrefix = fPrefix ? pEnumMap->pszPrefix : "";
+ if (pszValueName)
+ {
+ if (pszName)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %s%s (%#x)", pszName, pszPrefix, pszValueName, iValue);
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "%s%s (%#x)", pszPrefix, pszValueName, iValue);
+ return pszBuffer;
+ }
+
+ if (pszName)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %sUNKNOWN_%d (%#x)", pszName, pszPrefix, iValue, iValue);
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "%sUNKNOWN_%d (%#x)", pszPrefix, iValue, iValue);
+ return pszBuffer;
+}
+
+
+/**
+ * Formats an enum value as a string.
+ *
+ * @returns pszBuffer.
+ * @param pszBuffer The output buffer.
+ * @param cbBuffer The size of the output buffer.
+ * @param pszName The variable name, optional.
+ * @param uValue The enum value.
+ * @param pszPrefix The prefix of the enum values. Empty string if
+ * none. This helps reduce the memory footprint
+ * as well as the source code size.
+ * @param papszValues One to one string mapping of the enum values.
+ * @param cValues The number of values in the mapping.
+ */
+char *vmsvgaFormatEnumValue(char *pszBuffer, size_t cbBuffer, const char *pszName, uint32_t uValue,
+ const char *pszPrefix, const char * const *papszValues, size_t cValues)
+{
+ if (uValue < cValues)
+ {
+ if (pszName)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %s%s (%#x)", pszName, pszPrefix, papszValues[uValue], uValue);
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "%s%s (%#x)", pszPrefix, papszValues[uValue], uValue);
+ }
+ else
+ {
+ if (pszName)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %sUNKNOWN_%d (%#x)", pszName, pszPrefix, uValue, uValue);
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "%sUNKNOWN_%d (%#x)", pszPrefix, uValue, uValue);
+ }
+ return pszBuffer;
+}
+
+
+/**
+ * DBGF info printer for vmsvga3dAsciiPrint.
+ *
+ * @param pszLine The line to print.
+ * @param pvUser The debug info helpers.
+ */
+DECLCALLBACK(void) vmsvga3dAsciiPrintlnInfo(const char *pszLine, void *pvUser)
+{
+ PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
+ pHlp->pfnPrintf(pHlp, ">%s<\n", pszLine);
+}
+
+
+/**
+ * Log printer for vmsvga3dAsciiPrint.
+ *
+ * @param pszLine The line to print.
+ * @param pvUser Ignored.
+ */
+DECLCALLBACK(void) vmsvga3dAsciiPrintlnLog(const char *pszLine, void *pvUser)
+{
+ size_t cch = strlen(pszLine);
+ while (cch > 0 && pszLine[cch - 1] == ' ')
+ cch--;
+ RTLogPrintf("%.*s\n", cch, pszLine);
+ NOREF(pvUser);
+}
+
+
+void vmsvga3dAsciiPrint(PFMVMSVGAASCIIPRINTLN pfnPrintLine, void *pvUser, void const *pvImage, size_t cbImage,
+ uint32_t cx, uint32_t cy, uint32_t cbScanline, SVGA3dSurfaceFormat enmFormat, bool fInvY,
+ uint32_t cchMaxX, uint32_t cchMaxY)
+{
+ /*
+ * Skip stuff we can't or won't need to handle.
+ */
+ if (!cx || !cy)
+ return;
+ switch (enmFormat)
+ {
+ /* Compressed. */
+ case SVGA3D_DXT1:
+ case SVGA3D_DXT2:
+ case SVGA3D_DXT3:
+ case SVGA3D_DXT4:
+ case SVGA3D_DXT5:
+ return;
+ /* Generic. */
+ case SVGA3D_BUFFER:
+ return;
+ default:
+ break; /* ok */
+ }
+
+ /*
+ * Figure the pixel conversion factors.
+ */
+ uint32_t cxPerChar = cx / cchMaxX + 1;
+ uint32_t cyPerChar = cy / cchMaxY + 1;
+ /** @todo try keep aspect... */
+ uint32_t const cchLine = (cx + cxPerChar - 1) / cxPerChar;
+ uint32_t const cbSrcPixel = vmsvga3dSurfaceFormatSize(enmFormat);
+
+ /*
+ * The very simple conversion we're doing in this function is based on
+ * mapping a block of converted pixels to an ASCII character of similar
+ * weigth. We do that by summing up all the 8-bit gray scale pixels in
+ * that block, applying a conversion factor and getting an index into an
+ * array of increasingly weighty characters.
+ */
+ static const char s_szPalette[] = " ..`',:;icodxkO08XNWM";
+ static const uint32_t s_cchPalette = sizeof(s_szPalette) - 1;
+ uint32_t const cPixelsWeightPerChar = cxPerChar * cyPerChar * 256;
+
+ /*
+ * Do the work
+ */
+ uint32_t *pauScanline = (uint32_t *)RTMemTmpAllocZ(sizeof(pauScanline[0]) * cchLine + cchLine + 1);
+ if (!pauScanline)
+ return;
+ char *pszLine = (char *)&pauScanline[cchLine];
+ RTCPTRUNION uSrc;
+ uSrc.pv = pvImage;
+ if (fInvY)
+ uSrc.pu8 += (cy - 1) * cbScanline;
+ uint32_t cyLeft = cy;
+ uint32_t cyLeftInScanline = cyPerChar;
+ bool fHitFormatAssert = false;
+ for (;;)
+ {
+ /*
+ * Process the scanline. This is tedious because of all the
+ * different formats. We generally ignore alpha, unless it's
+ * all we've got to work with.
+ * Color to 8-bit grayscale conversion is done by averaging.
+ */
+#define CONVERT_SCANLINE(a_RdExpr, a_AddExpr) \
+ do { \
+ for (uint32_t xSrc = 0, xDst = 0, cxLeftInChar = cxPerChar; xSrc < cx; xSrc++) \
+ { \
+ a_RdExpr; \
+ pauScanline[xDst] += (a_AddExpr) & 0xff; \
+ Assert(pauScanline[xDst] <= cPixelsWeightPerChar); \
+ if (--cxLeftInChar == 0) \
+ { \
+ xDst++; \
+ cxLeftInChar = cxPerChar; \
+ } \
+ } \
+ } while (0)
+
+ switch (enmFormat)
+ {
+ /* Unsigned RGB and super/subsets. */
+ case SVGA3D_X8R8G8B8:
+ case SVGA3D_A8R8G8B8:
+ CONVERT_SCANLINE(uint32_t const u32Tmp = uSrc.pu32[xSrc],
+ ( ( u32Tmp & 0xff) /* B */
+ + ((u32Tmp >> 8) & 0xff) /* G */
+ + ((u32Tmp >> 16) & 0xff) /* R */) / 3);
+ break;
+ case SVGA3D_R5G6B5:
+ CONVERT_SCANLINE(uint16_t const u16Tmp = uSrc.pu16[xSrc],
+ ( ( u16Tmp & 0x1f) * 8
+ + ((u16Tmp >> 5) & 0x3f) * 4
+ + ( u16Tmp >> 11) * 8 ) / 3 );
+ break;
+ case SVGA3D_X1R5G5B5:
+ case SVGA3D_A1R5G5B5:
+ CONVERT_SCANLINE(uint16_t const u16Tmp = uSrc.pu16[xSrc],
+ ( ( u16Tmp & 0x1f) * 8
+ + ((u16Tmp >> 5) & 0x1f) * 8
+ + ((u16Tmp >> 10) & 0x1f) * 8) / 3 );
+ break;
+ case SVGA3D_A4R4G4B4:
+ CONVERT_SCANLINE(uint16_t const u16Tmp = uSrc.pu16[xSrc],
+ ( ( u16Tmp & 0xf) * 16
+ + ((u16Tmp >> 4) & 0xf) * 16
+ + ((u16Tmp >> 8) & 0xf) * 16) / 3 );
+ break;
+ case SVGA3D_A16B16G16R16:
+ CONVERT_SCANLINE(uint64_t const u64Tmp = uSrc.pu64[xSrc],
+ ( ((u64Tmp >> 8) & 0xff) /* R */
+ + ((u64Tmp >> 24) & 0xff) /* G */
+ + ((u64Tmp >> 40) & 0xff) /* B */ ) / 3);
+ break;
+ case SVGA3D_A2R10G10B10:
+ CONVERT_SCANLINE(uint32_t const u32Tmp = uSrc.pu32[xSrc],
+ ( ( u32Tmp & 0x3ff) /* B */
+ + ((u32Tmp >> 10) & 0x3ff) /* G */
+ + ((u32Tmp >> 20) & 0x3ff) /* R */ ) / (3 * 4));
+ break;
+ case SVGA3D_G16R16:
+ CONVERT_SCANLINE(uint32_t const u32Tmp = uSrc.pu32[xSrc],
+ ( (u32Tmp & 0xffff) /* R */
+ + (u32Tmp >> 16 ) /* G */) / 0x200);
+ break;
+
+ /* Depth. */
+ case SVGA3D_Z_D32:
+ CONVERT_SCANLINE(uint32_t const u32Tmp = ~((uSrc.pu32[xSrc] >> 1) | uSrc.pu32[xSrc]) & UINT32_C(0x44444444),
+ (( u32Tmp >> (2 - 0)) & RT_BIT_32(0))
+ | ((u32Tmp >> ( 6 - 1)) & RT_BIT_32(1))
+ | ((u32Tmp >> (10 - 2)) & RT_BIT_32(2))
+ | ((u32Tmp >> (14 - 3)) & RT_BIT_32(3))
+ | ((u32Tmp >> (18 - 4)) & RT_BIT_32(4))
+ | ((u32Tmp >> (22 - 5)) & RT_BIT_32(5))
+ | ((u32Tmp >> (26 - 6)) & RT_BIT_32(6))
+ | ((u32Tmp >> (30 - 7)) & RT_BIT_32(7)) );
+ break;
+ case SVGA3D_Z_D16:
+ CONVERT_SCANLINE(uint16_t const u16Tmp = ~uSrc.pu16[xSrc],
+ ((u16Tmp >> ( 1 - 0)) & RT_BIT_32(0))
+ | ((u16Tmp >> ( 3 - 1)) & RT_BIT_32(1))
+ | ((u16Tmp >> ( 5 - 2)) & RT_BIT_32(2))
+ | ((u16Tmp >> ( 7 - 3)) & RT_BIT_32(3))
+ | ((u16Tmp >> ( 9 - 4)) & RT_BIT_32(4))
+ | ((u16Tmp >> (11 - 5)) & RT_BIT_32(5))
+ | ((u16Tmp >> (13 - 6)) & RT_BIT_32(6))
+ | ((u16Tmp >> (15 - 7)) & RT_BIT_32(7)) );
+ break;
+ case SVGA3D_Z_D24S8:
+ CONVERT_SCANLINE(uint32_t const u32Tmp = uSrc.pu32[xSrc],
+ ( u32Tmp & 0xff) /* stencile */
+ | ((~u32Tmp >> 18) & 0x3f));
+ break;
+ case SVGA3D_Z_D15S1:
+ CONVERT_SCANLINE(uint16_t const u16Tmp = uSrc.pu16[xSrc],
+ ( (u16Tmp & 0x01) << 7) /* stencile */
+ | ((~u16Tmp >> 8) & 0x7f));
+ break;
+
+ /* Pure alpha. */
+ case SVGA3D_ALPHA8:
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu8[xSrc]);
+ break;
+
+ /* Luminance */
+ case SVGA3D_LUMINANCE8:
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu8[xSrc]);
+ break;
+ case SVGA3D_LUMINANCE4_ALPHA4:
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu8[xSrc] & 0xf0);
+ break;
+ case SVGA3D_LUMINANCE16:
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu16[xSrc] >> 8);
+ break;
+ case SVGA3D_LUMINANCE8_ALPHA8:
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu16[xSrc] >> 8);
+ break;
+
+ /* Not supported. */
+ case SVGA3D_DXT1:
+ case SVGA3D_DXT2:
+ case SVGA3D_DXT3:
+ case SVGA3D_DXT4:
+ case SVGA3D_DXT5:
+ case SVGA3D_BUFFER:
+ AssertFailedBreak();
+
+ /* Not considered for implementation yet. */
+ case SVGA3D_BUMPU8V8:
+ case SVGA3D_BUMPL6V5U5:
+ case SVGA3D_BUMPX8L8V8U8:
+ case SVGA3D_BUMPL8V8U8:
+ case SVGA3D_ARGB_S10E5:
+ case SVGA3D_ARGB_S23E8:
+ case SVGA3D_V8U8:
+ case SVGA3D_Q8W8V8U8:
+ case SVGA3D_CxV8U8:
+ case SVGA3D_X8L8V8U8:
+ case SVGA3D_A2W10V10U10:
+ case SVGA3D_R_S10E5:
+ case SVGA3D_R_S23E8:
+ case SVGA3D_RG_S10E5:
+ case SVGA3D_RG_S23E8:
+ case SVGA3D_Z_D24X8:
+ case SVGA3D_V16U16:
+ case SVGA3D_UYVY:
+ case SVGA3D_YUY2:
+ case SVGA3D_NV12:
+ case SVGA3D_AYUV:
+ case SVGA3D_BC4_UNORM:
+ case SVGA3D_BC5_UNORM:
+ case SVGA3D_Z_DF16:
+ case SVGA3D_Z_DF24:
+ case SVGA3D_Z_D24S8_INT:
+ if (!fHitFormatAssert)
+ {
+ AssertMsgFailed(("%s is not implemented\n", vmsvgaLookupEnum((int)enmFormat, &g_SVGA3dSurfaceFormat2String)));
+ fHitFormatAssert = true;
+ }
+ /* fall thru */
+ default:
+ /* Lazy programmer fallbacks. */
+ if (cbSrcPixel == 4)
+ CONVERT_SCANLINE(uint32_t const u32Tmp = uSrc.pu32[xSrc],
+ ( ( u32Tmp & 0xff)
+ + ((u32Tmp >> 8) & 0xff)
+ + ((u32Tmp >> 16) & 0xff)
+ + ((u32Tmp >> 24) & 0xff) ) / 4);
+ else if (cbSrcPixel == 3)
+ CONVERT_SCANLINE(RT_NOTHING,
+ ( (uint32_t)uSrc.pu8[xSrc * 4]
+ + (uint32_t)uSrc.pu8[xSrc * 4 + 1]
+ + (uint32_t)uSrc.pu8[xSrc * 4 + 2] ) / 3);
+ else if (cbSrcPixel == 2)
+ CONVERT_SCANLINE(uint16_t const u16Tmp = uSrc.pu16[xSrc],
+ ( ( u16Tmp & 0xf)
+ + ((u16Tmp >> 4) & 0xf)
+ + ((u16Tmp >> 8) & 0xf)
+ + ((u16Tmp >> 12) & 0xf) ) * 4 /* mul 16 div 4 */ );
+ else if (cbSrcPixel == 1)
+ CONVERT_SCANLINE(RT_NOTHING, uSrc.pu8[xSrc]);
+ else
+ AssertFailed();
+ break;
+
+ }
+
+ /*
+ * Print we've reached the end of a block in y direction or if we're at
+ * the end of the image.
+ */
+ cyLeft--;
+ if (--cyLeftInScanline == 0 || cyLeft == 0)
+ {
+ for (uint32_t i = 0; i < cchLine; i++)
+ {
+ uint32_t off = pauScanline[i] * s_cchPalette / cPixelsWeightPerChar; Assert(off < s_cchPalette);
+ pszLine[i] = s_szPalette[off < sizeof(s_szPalette) - 1 ? off : sizeof(s_szPalette) - 1];
+ }
+ pszLine[cchLine] = '\0';
+ pfnPrintLine(pszLine, pvUser);
+
+ if (!cyLeft)
+ break;
+ cyLeftInScanline = cyPerChar;
+ RT_BZERO(pauScanline, sizeof(pauScanline[0]) * cchLine);
+ }
+
+ /*
+ * Advance.
+ */
+ if (!fInvY)
+ uSrc.pu8 += cbScanline;
+ else
+ uSrc.pu8 -= cbScanline;
+ }
+}
+
+
+
+/**
+ * Formats a SVGA3dRenderState structure as a string.
+ *
+ * @returns pszBuffer.
+ * @param pszBuffer Output string buffer.
+ * @param cbBuffer Size of output buffer.
+ * @param pRenderState The SVGA3d render state to format.
+ */
+char *vmsvga3dFormatRenderState(char *pszBuffer, size_t cbBuffer, SVGA3dRenderState const *pRenderState)
+{
+ /*
+ * List of render state names with type prefix.
+ *
+ * First char in the name is a type indicator:
+ * - '*' = requires special handling.
+ * - 'f' = SVGA3dbool
+ * - 'd' = uint32_t
+ * - 'r' = float
+ * - 'b' = SVGA3dBlendOp
+ * - 'c' = SVGA3dColor, SVGA3dColorMask
+ * - 'e' = SVGA3dBlendEquation
+ * - 'm' = SVGA3dColorMask
+ * - 'p' = SVGA3dCmpFunc
+ * - 's' = SVGA3dStencilOp
+ * - 'v' = SVGA3dVertexMaterial
+ * - 'w' = SVGA3dWrapFlags
+ */
+ static const char * const s_apszRenderStateNamesAndType[] =
+ {
+ "*" "INVALID", /* invalid */
+ "f" "ZENABLE", /* SVGA3dBool */
+ "f" "ZWRITEENABLE", /* SVGA3dBool */
+ "f" "ALPHATESTENABLE", /* SVGA3dBool */
+ "f" "DITHERENABLE", /* SVGA3dBool */
+ "f" "BLENDENABLE", /* SVGA3dBool */
+ "f" "FOGENABLE", /* SVGA3dBool */
+ "f" "SPECULARENABLE", /* SVGA3dBool */
+ "f" "STENCILENABLE", /* SVGA3dBool */
+ "f" "LIGHTINGENABLE", /* SVGA3dBool */
+ "f" "NORMALIZENORMALS", /* SVGA3dBool */
+ "f" "POINTSPRITEENABLE", /* SVGA3dBool */
+ "f" "POINTSCALEENABLE", /* SVGA3dBool */
+ "x" "STENCILREF", /* uint32_t */
+ "x" "STENCILMASK", /* uint32_t */
+ "x" "STENCILWRITEMASK", /* uint32_t */
+ "r" "FOGSTART", /* float */
+ "r" "FOGEND", /* float */
+ "r" "FOGDENSITY", /* float */
+ "r" "POINTSIZE", /* float */
+ "r" "POINTSIZEMIN", /* float */
+ "r" "POINTSIZEMAX", /* float */
+ "r" "POINTSCALE_A", /* float */
+ "r" "POINTSCALE_B", /* float */
+ "r" "POINTSCALE_C", /* float */
+ "c" "FOGCOLOR", /* SVGA3dColor */
+ "c" "AMBIENT", /* SVGA3dColor */
+ "*" "CLIPPLANEENABLE", /* SVGA3dClipPlanes */
+ "*" "FOGMODE", /* SVGA3dFogMode */
+ "*" "FILLMODE", /* SVGA3dFillMode */
+ "*" "SHADEMODE", /* SVGA3dShadeMode */
+ "*" "LINEPATTERN", /* SVGA3dLinePattern */
+ "b" "SRCBLEND", /* SVGA3dBlendOp */
+ "b" "DSTBLEND", /* SVGA3dBlendOp */
+ "e" "BLENDEQUATION", /* SVGA3dBlendEquation */
+ "*" "CULLMODE", /* SVGA3dFace */
+ "p" "ZFUNC", /* SVGA3dCmpFunc */
+ "p" "ALPHAFUNC", /* SVGA3dCmpFunc */
+ "p" "STENCILFUNC", /* SVGA3dCmpFunc */
+ "s" "STENCILFAIL", /* SVGA3dStencilOp */
+ "s" "STENCILZFAIL", /* SVGA3dStencilOp */
+ "s" "STENCILPASS", /* SVGA3dStencilOp */
+ "r" "ALPHAREF", /* float */
+ "*" "FRONTWINDING", /* SVGA3dFrontWinding */
+ "*" "COORDINATETYPE", /* SVGA3dCoordinateType */
+ "r" "ZBIAS", /* float */
+ "f" "RANGEFOGENABLE", /* SVGA3dBool */
+ "c" "COLORWRITEENABLE", /* SVGA3dColorMask */
+ "f" "VERTEXMATERIALENABLE", /* SVGA3dBool */
+ "v" "DIFFUSEMATERIALSOURCE", /* SVGA3dVertexMaterial */
+ "v" "SPECULARMATERIALSOURCE", /* SVGA3dVertexMaterial */
+ "v" "AMBIENTMATERIALSOURCE", /* SVGA3dVertexMaterial */
+ "v" "EMISSIVEMATERIALSOURCE", /* SVGA3dVertexMaterial */
+ "c" "TEXTUREFACTOR", /* SVGA3dColor */
+ "f" "LOCALVIEWER", /* SVGA3dBool */
+ "f" "SCISSORTESTENABLE", /* SVGA3dBool */
+ "c" "BLENDCOLOR", /* SVGA3dColor */
+ "f" "STENCILENABLE2SIDED", /* SVGA3dBool */
+ "p" "CCWSTENCILFUNC", /* SVGA3dCmpFunc */
+ "s" "CCWSTENCILFAIL", /* SVGA3dStencilOp */
+ "s" "CCWSTENCILZFAIL", /* SVGA3dStencilOp */
+ "s" "CCWSTENCILPASS", /* SVGA3dStencilOp */
+ "*" "VERTEXBLEND", /* SVGA3dVertexBlendFlags */
+ "r" "SLOPESCALEDEPTHBIAS", /* float */
+ "r" "DEPTHBIAS", /* float */
+ "r" "OUTPUTGAMMA", /* float */
+ "f" "ZVISIBLE", /* SVGA3dBool */
+ "f" "LASTPIXEL", /* SVGA3dBool */
+ "f" "CLIPPING", /* SVGA3dBool */
+ "w" "WRAP0", /* SVGA3dWrapFlags */
+ "w" "WRAP1", /* SVGA3dWrapFlags */
+ "w" "WRAP2", /* SVGA3dWrapFlags */
+ "w" "WRAP3", /* SVGA3dWrapFlags */
+ "w" "WRAP4", /* SVGA3dWrapFlags */
+ "w" "WRAP5", /* SVGA3dWrapFlags */
+ "w" "WRAP6", /* SVGA3dWrapFlags */
+ "w" "WRAP7", /* SVGA3dWrapFlags */
+ "w" "WRAP8", /* SVGA3dWrapFlags */
+ "w" "WRAP9", /* SVGA3dWrapFlags */
+ "w" "WRAP10", /* SVGA3dWrapFlags */
+ "w" "WRAP11", /* SVGA3dWrapFlags */
+ "w" "WRAP12", /* SVGA3dWrapFlags */
+ "w" "WRAP13", /* SVGA3dWrapFlags */
+ "w" "WRAP14", /* SVGA3dWrapFlags */
+ "w" "WRAP15", /* SVGA3dWrapFlags */
+ "f" "MULTISAMPLEANTIALIAS", /* SVGA3dBool */
+ "x" "MULTISAMPLEMASK", /* uint32_t */
+ "f" "INDEXEDVERTEXBLENDENABLE", /* SVGA3dBool */
+ "r" "TWEENFACTOR", /* float */
+ "f" "ANTIALIASEDLINEENABLE", /* SVGA3dBool */
+ "c" "COLORWRITEENABLE1", /* SVGA3dColorMask */
+ "c" "COLORWRITEENABLE2", /* SVGA3dColorMask */
+ "c" "COLORWRITEENABLE3", /* SVGA3dColorMask */
+ "f" "SEPARATEALPHABLENDENABLE", /* SVGA3dBool */
+ "b" "SRCBLENDALPHA", /* SVGA3dBlendOp */
+ "b" "DSTBLENDALPHA", /* SVGA3dBlendOp */
+ "e" "BLENDEQUATIONALPHA", /* SVGA3dBlendEquation */
+ "*" "TRANSPARENCYANTIALIAS", /* SVGA3dTransparencyAntialiasType */
+ "f" "LINEAA", /* SVGA3dBool */
+ "r" "LINEWIDTH", /* float */
+ };
+
+ uint32_t iState = pRenderState->state;
+ if (iState != SVGA3D_RS_INVALID)
+ {
+ if (iState < RT_ELEMENTS(s_apszRenderStateNamesAndType))
+ {
+ const char *pszName = s_apszRenderStateNamesAndType[iState];
+ char const chType = *pszName++;
+
+ union
+ {
+ uint32_t u;
+ float r;
+ SVGA3dColorMask Color;
+ } uValue;
+ uValue.u = pRenderState->uintValue;
+
+ switch (chType)
+ {
+ case 'f':
+ if (uValue.u == 0)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = false", pszName);
+ else if (uValue.u == 1)
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = true", pszName);
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = true (%#x)", pszName, uValue.u);
+ break;
+ case 'x':
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %#x (%d)", pszName, uValue.u, uValue.u);
+ break;
+ case 'r':
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %d.%06u (%#x)",
+ pszName, (int)uValue.r, (unsigned)(uValue.r * 1000000) % 1000000U, uValue.u);
+ break;
+ case 'c': //SVGA3dColor, SVGA3dColorMask
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = RGBA(%d,%d,%d,%d) (%#x)", pszName,
+ uValue.Color.s.red, uValue.Color.s.green, uValue.Color.s.blue, uValue.Color.s.alpha, uValue.u);
+ break;
+ case 'w': //SVGA3dWrapFlags
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %#x%s", pszName, uValue.u,
+ uValue.u <= SVGA3D_WRAPCOORD_ALL ? " (out of bounds" : "");
+ break;
+ default:
+ AssertFailed();
+ case 'b': //SVGA3dBlendOp
+ case 'e': //SVGA3dBlendEquation
+ case 'p': //SVGA3dCmpFunc
+ case 's': //SVGA3dStencilOp
+ case 'v': //SVGA3dVertexMaterial
+ case '*':
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %#x", pszName, uValue.u);
+ break;
+ }
+ }
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "UNKNOWN_%d_%#x = %#x", iState, iState, pRenderState->uintValue);
+ }
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "INVALID");
+ return pszBuffer;
+}
+
+
+/**
+ * Formats a SVGA3dTextureState structure as a string.
+ *
+ * @returns pszBuffer.
+ * @param pszBuffer Output string buffer.
+ * @param cbBuffer Size of output buffer.
+ * @param pTextureState The SVGA3d texture state to format.
+ */
+char *vmsvga3dFormatTextureState(char *pszBuffer, size_t cbBuffer, SVGA3dTextureState const *pTextureState)
+{
+ static const char * const s_apszTextureStateNamesAndType[] =
+ {
+ "*" "INVALID", /* invalid */
+ "x" "BIND_TEXTURE", /* SVGA3dSurfaceId */
+ "m" "COLOROP", /* SVGA3dTextureCombiner */
+ "a" "COLORARG1", /* SVGA3dTextureArgData */
+ "a" "COLORARG2", /* SVGA3dTextureArgData */
+ "m" "ALPHAOP", /* SVGA3dTextureCombiner */
+ "a" "ALPHAARG1", /* SVGA3dTextureArgData */
+ "a" "ALPHAARG2", /* SVGA3dTextureArgData */
+ "e" "ADDRESSU", /* SVGA3dTextureAddress */
+ "e" "ADDRESSV", /* SVGA3dTextureAddress */
+ "l" "MIPFILTER", /* SVGA3dTextureFilter */
+ "l" "MAGFILTER", /* SVGA3dTextureFilter */
+ "m" "MINFILTER", /* SVGA3dTextureFilter */
+ "c" "BORDERCOLOR", /* SVGA3dColor */
+ "r" "TEXCOORDINDEX", /* uint32_t */
+ "t" "TEXTURETRANSFORMFLAGS", /* SVGA3dTexTransformFlags */
+ "g" "TEXCOORDGEN", /* SVGA3dTextureCoordGen */
+ "r" "BUMPENVMAT00", /* float */
+ "r" "BUMPENVMAT01", /* float */
+ "r" "BUMPENVMAT10", /* float */
+ "r" "BUMPENVMAT11", /* float */
+ "x" "TEXTURE_MIPMAP_LEVEL", /* uint32_t */
+ "r" "TEXTURE_LOD_BIAS", /* float */
+ "x" "TEXTURE_ANISOTROPIC_LEVEL", /* uint32_t */
+ "e" "ADDRESSW", /* SVGA3dTextureAddress */
+ "r" "GAMMA", /* float */
+ "r" "BUMPENVLSCALE", /* float */
+ "r" "BUMPENVLOFFSET", /* float */
+ "a" "COLORARG0", /* SVGA3dTextureArgData */
+ "a" "ALPHAARG0" /* SVGA3dTextureArgData */
+ };
+
+ /*
+ * Format the stage first.
+ */
+ char *pszRet = pszBuffer;
+ size_t cchPrefix = RTStrPrintf(pszBuffer, cbBuffer, "[%u] ", pTextureState->stage);
+ if (cchPrefix < cbBuffer)
+ {
+ cbBuffer -= cchPrefix;
+ pszBuffer += cchPrefix;
+ }
+ else
+ cbBuffer = 0;
+
+ /*
+ * Format the name and value.
+ */
+ uint32_t iName = pTextureState->name;
+ if (iName != SVGA3D_TS_INVALID)
+ {
+ if (iName < RT_ELEMENTS(s_apszTextureStateNamesAndType))
+ {
+ const char *pszName = s_apszTextureStateNamesAndType[iName];
+ char chType = *pszName++;
+
+ union
+ {
+ uint32_t u;
+ float r;
+ SVGA3dColorMask Color;
+ } uValue;
+ uValue.u = pTextureState->value;
+
+ switch (chType)
+ {
+ case 'x':
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %#x (%d)", pszName, uValue.u, uValue.u);
+ break;
+
+ case 'r':
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %d.%06u (%#x)",
+ pszName, (int)uValue.r, (unsigned)(uValue.r * 1000000) % 1000000U, uValue.u);
+ break;
+
+ case 'a': //SVGA3dTextureArgData
+ {
+ static const char * const s_apszValues[] =
+ {
+ "INVALID", "CONSTANT", "PREVIOUS", "DIFFUSE", "TEXTURE", "SPECULAR"
+ };
+ vmsvgaFormatEnumValue(pszBuffer, cbBuffer, pszName, uValue.u,
+ "SVGA3D_TA_", s_apszValues, RT_ELEMENTS(s_apszValues));
+ break;
+ }
+
+ case 'c': //SVGA3dColor, SVGA3dColorMask
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = RGBA(%d,%d,%d,%d) (%#x)", pszName,
+ uValue.Color.s.red, uValue.Color.s.green, uValue.Color.s.blue, uValue.Color.s.alpha, uValue.u);
+ break;
+
+ case 'e': //SVGA3dTextureAddress
+ {
+ static const char * const s_apszValues[] =
+ {
+ "INVALID", "WRAP", "MIRROR", "CLAMP", "BORDER", "MIRRORONCE", "EDGE",
+ };
+ vmsvgaFormatEnumValue(pszBuffer, cbBuffer, pszName, uValue.u,
+ "SVGA3D_TEX_ADDRESS_", s_apszValues, RT_ELEMENTS(s_apszValues));
+ break;
+ }
+
+ case 'l': //SVGA3dTextureFilter
+ {
+ static const char * const s_apszValues[] =
+ {
+ "NONE", "NEAREST", "LINEAR", "ANISOTROPIC", "FLATCUBIC", "GAUSSIANCUBIC", "PYRAMIDALQUAD", "GAUSSIANQUAD",
+ };
+ vmsvgaFormatEnumValue(pszBuffer, cbBuffer, pszName, uValue.u,
+ "SVGA3D_TEX_FILTER_", s_apszValues, RT_ELEMENTS(s_apszValues));
+ break;
+ }
+
+ case 'g': //SVGA3dTextureCoordGen
+ {
+ static const char * const s_apszValues[] =
+ {
+ "OFF", "EYE_POSITION", "EYE_NORMAL", "REFLECTIONVECTOR", "SPHERE",
+ };
+ vmsvgaFormatEnumValue(pszBuffer, cbBuffer, pszName, uValue.u,
+ "SVGA3D_TEXCOORD_GEN_", s_apszValues, RT_ELEMENTS(s_apszValues));
+ break;
+ }
+
+ case 'm': //SVGA3dTextureCombiner
+ {
+ static const char * const s_apszValues[] =
+ {
+ "INVALID", "DISABLE", "SELECTARG1", "SELECTARG2", "MODULATE", "ADD", "ADDSIGNED", "SUBTRACT",
+ "BLENDTEXTUREALPHA", "BLENDDIFFUSEALPHA", "BLENDCURRENTALPHA", "BLENDFACTORALPHA", "MODULATE2X",
+ "MODULATE4X", "DSDT", "DOTPRODUCT3", "BLENDTEXTUREALPHAPM", "ADDSIGNED2X", "ADDSMOOTH", "PREMODULATE",
+ "MODULATEALPHA_ADDCOLOR", "MODULATECOLOR_ADDALPHA", "MODULATEINVALPHA_ADDCOLOR",
+ "MODULATEINVCOLOR_ADDALPHA", "BUMPENVMAPLUMINANCE", "MULTIPLYADD", "LERP",
+ };
+ vmsvgaFormatEnumValue(pszBuffer, cbBuffer, pszName, uValue.u,
+ "SVGA3D_TC_", s_apszValues, RT_ELEMENTS(s_apszValues));
+ break;
+ }
+
+ default:
+ AssertFailed();
+ RTStrPrintf(pszBuffer, cbBuffer, "%s = %#x\n", pszName, uValue.u);
+ break;
+ }
+ }
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "UNKNOWN_%d_%#x = %#x\n", iName, iName, pTextureState->value);
+ }
+ else
+ RTStrPrintf(pszBuffer, cbBuffer, "INVALID");
+ return pszRet;
+}
+
+
+
+static const char * const g_apszTransformTypes[] =
+{
+ "SVGA3D_TRANSFORM_INVALID",
+ "SVGA3D_TRANSFORM_WORLD",
+ "SVGA3D_TRANSFORM_VIEW",
+ "SVGA3D_TRANSFORM_PROJECTION",
+ "SVGA3D_TRANSFORM_TEXTURE0",
+ "SVGA3D_TRANSFORM_TEXTURE1",
+ "SVGA3D_TRANSFORM_TEXTURE2",
+ "SVGA3D_TRANSFORM_TEXTURE3",
+ "SVGA3D_TRANSFORM_TEXTURE4",
+ "SVGA3D_TRANSFORM_TEXTURE5",
+ "SVGA3D_TRANSFORM_TEXTURE6",
+ "SVGA3D_TRANSFORM_TEXTURE7",
+ "SVGA3D_TRANSFORM_WORLD1",
+ "SVGA3D_TRANSFORM_WORLD2",
+ "SVGA3D_TRANSFORM_WORLD3",
+};
+
+static const char * const g_apszFaces[] =
+{
+ "SVGA3D_FACE_INVALID",
+ "SVGA3D_FACE_NONE",
+ "SVGA3D_FACE_FRONT",
+ "SVGA3D_FACE_BACK",
+ "SVGA3D_FACE_FRONT_BACK",
+};
+
+static const char * const g_apszLightTypes[] =
+{
+ "SVGA3D_LIGHTTYPE_INVALID",
+ "SVGA3D_LIGHTTYPE_POINT",
+ "SVGA3D_LIGHTTYPE_SPOT1",
+ "SVGA3D_LIGHTTYPE_SPOT2",
+ "SVGA3D_LIGHTTYPE_DIRECTIONAL",
+};
+
+static const char * const g_apszRenderTargets[] =
+{
+ "SVGA3D_RT_DEPTH",
+ "SVGA3D_RT_STENCIL",
+ "SVGA3D_RT_COLOR0",
+ "SVGA3D_RT_COLOR1",
+ "SVGA3D_RT_COLOR2",
+ "SVGA3D_RT_COLOR3",
+ "SVGA3D_RT_COLOR4",
+ "SVGA3D_RT_COLOR5",
+ "SVGA3D_RT_COLOR6",
+ "SVGA3D_RT_COLOR7",
+};
+
+static void vmsvga3dInfoContextWorkerOne(PCDBGFINFOHLP pHlp, PVMSVGA3DCONTEXT pContext, bool fVerbose)
+{
+ char szTmp[128];
+
+ pHlp->pfnPrintf(pHlp, "*** VMSVGA 3d context %#x (%d) ***\n", pContext->id, pContext->id);
+#ifdef RT_OS_WINDOWS
+ pHlp->pfnPrintf(pHlp, "hwnd: %p\n", pContext->hwnd);
+ if (fVerbose)
+ vmsvga3dInfoHostWindow(pHlp, (uintptr_t)pContext->hwnd);
+# ifdef VMSVGA3D_DIRECT3D
+ pHlp->pfnPrintf(pHlp, "pDevice: %p\n", pContext->pDevice);
+# else
+ pHlp->pfnPrintf(pHlp, "hdc: %p\n", pContext->hdc);
+ pHlp->pfnPrintf(pHlp, "hglrc: %p\n", pContext->hglrc);
+# endif
+
+#elif defined(RT_OS_DARWIN)
+ pHlp->pfnPrintf(pHlp, "cocoaView: %p\n", pContext->cocoaView);
+ if (pContext->cocoaView)
+ vmsvga3dInfoHostWindow(pHlp, (uintptr_t)pContext->cocoaView);
+ pHlp->pfnPrintf(pHlp, "cocoaContext: %p\n", pContext->cocoaContext);
+ if (pContext->fOtherProfile)
+ pHlp->pfnPrintf(pHlp, "fOtherProfile: true\n");
+
+#else
+ pHlp->pfnPrintf(pHlp, "window: %p\n", pContext->window);
+ pHlp->pfnPrintf(pHlp, "fMapped: %RTbool\n", pContext->fMapped);
+ if (pContext->window)
+ vmsvga3dInfoHostWindow(pHlp, (uintptr_t)pContext->window);
+ pHlp->pfnPrintf(pHlp, "glxContext: %p\n", pContext->glxContext);
+
+#endif
+ pHlp->pfnPrintf(pHlp, "sidRenderTarget: %#x\n", pContext->sidRenderTarget);
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->aSidActiveTexture); i++)
+ if (pContext->aSidActiveTexture[i] != SVGA3D_INVALID_ID)
+ pHlp->pfnPrintf(pHlp, "aSidActiveTexture[%u]: %#x\n", i, pContext->aSidActiveTexture[i]);
+
+ pHlp->pfnPrintf(pHlp, "fUpdateFlags: %#x\n", pContext->state.u32UpdateFlags);
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aRenderState); i++)
+ if (pContext->state.aRenderState[i].state != SVGA3D_RS_INVALID)
+ pHlp->pfnPrintf(pHlp, "aRenderState[%3d]: %s\n", i,
+ vmsvga3dFormatRenderState(szTmp, sizeof(szTmp), &pContext->state.aRenderState[i]));
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aTextureState); i++)
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aTextureState[i]); j++)
+ if (pContext->state.aTextureState[i][j].name != SVGA3D_TS_INVALID)
+ pHlp->pfnPrintf(pHlp, "aTextureState[%3d][%3d]: %s\n", i, j,
+ vmsvga3dFormatTextureState(szTmp, sizeof(szTmp), &pContext->state.aTextureState[i][j]));
+
+ AssertCompile(RT_ELEMENTS(g_apszTransformTypes) == SVGA3D_TRANSFORM_MAX);
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aTransformState); i++)
+ if (pContext->state.aTransformState[i].fValid)
+ {
+ pHlp->pfnPrintf(pHlp, "aTransformState[%s(%u)]:\n", g_apszTransformTypes[i], i);
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aTransformState[i].matrix); j++)
+ pHlp->pfnPrintf(pHlp,
+ (j % 4) == 0 ? " [ " FLOAT_FMT_STR : (j % 4) < 3 ? ", " FLOAT_FMT_STR : ", " FLOAT_FMT_STR "]\n",
+ FLOAT_FMT_ARGS(pContext->state.aTransformState[i].matrix[j]));
+ }
+
+ AssertCompile(RT_ELEMENTS(g_apszFaces) == SVGA3D_FACE_MAX);
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aMaterial); i++)
+ if (pContext->state.aMaterial[i].fValid)
+ {
+ pHlp->pfnPrintf(pHlp, "aTransformState[%s(%u)]: shininess=" FLOAT_FMT_STR "\n",
+ g_apszFaces[i], i, FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.shininess));
+ pHlp->pfnPrintf(pHlp, " diffuse =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.diffuse[0]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.diffuse[1]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.diffuse[2]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.diffuse[3]));
+ pHlp->pfnPrintf(pHlp, " ambient =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.ambient[0]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.ambient[1]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.ambient[2]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.ambient[3]));
+ pHlp->pfnPrintf(pHlp, " specular=[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.specular[0]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.specular[1]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.specular[2]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.specular[3]));
+ pHlp->pfnPrintf(pHlp, " emissive=[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.emissive[0]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.emissive[1]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.emissive[2]),
+ FLOAT_FMT_ARGS(pContext->state.aMaterial[i].material.emissive[3]));
+ }
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aClipPlane); i++)
+ if (pContext->state.aClipPlane[i].fValid)
+ pHlp->pfnPrintf(pHlp, "aClipPlane[%#04x]: [ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aClipPlane[i].plane[0]),
+ FLOAT_FMT_ARGS(pContext->state.aClipPlane[i].plane[1]),
+ FLOAT_FMT_ARGS(pContext->state.aClipPlane[i].plane[2]),
+ FLOAT_FMT_ARGS(pContext->state.aClipPlane[i].plane[3]));
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aLightData); i++)
+ if (pContext->state.aLightData[i].fValidData)
+ {
+ pHlp->pfnPrintf(pHlp, "aLightData[%#04x]: enabled=%RTbool inWorldSpace=%RTbool type=%s(%u)\n",
+ i,
+ pContext->state.aLightData[i].fEnabled,
+ pContext->state.aLightData[i].data.inWorldSpace,
+ (uint32_t)pContext->state.aLightData[i].data.type < RT_ELEMENTS(g_apszLightTypes)
+ ? g_apszLightTypes[pContext->state.aLightData[i].data.type] : "UNKNOWN",
+ pContext->state.aLightData[i].data.type);
+ pHlp->pfnPrintf(pHlp, " diffuse =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.diffuse[0]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.diffuse[1]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.diffuse[2]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.diffuse[3]));
+ pHlp->pfnPrintf(pHlp, " specular =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.specular[0]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.specular[1]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.specular[2]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.specular[3]));
+ pHlp->pfnPrintf(pHlp, " ambient =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.ambient[0]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.ambient[1]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.ambient[2]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.ambient[3]));
+ pHlp->pfnPrintf(pHlp, " position =[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.position[0]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.position[1]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.position[2]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.position[3]));
+ pHlp->pfnPrintf(pHlp, " direction=[ " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR " ]\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.direction[0]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.direction[1]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.direction[2]),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.direction[3]));
+ pHlp->pfnPrintf(pHlp, " range=" FLOAT_FMT_STR " falloff=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.range),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.falloff));
+ pHlp->pfnPrintf(pHlp, " attenuation0=" FLOAT_FMT_STR " attenuation1=" FLOAT_FMT_STR " attenuation2=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.attenuation0),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.attenuation1),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.attenuation2));
+ pHlp->pfnPrintf(pHlp, " theta=" FLOAT_FMT_STR " phi=" FLOAT_FMT_STR "\n",
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.theta),
+ FLOAT_FMT_ARGS(pContext->state.aLightData[i].data.phi));
+ }
+
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->state.aRenderTargets); i++)
+ if (pContext->state.aRenderTargets[i] != SVGA3D_INVALID_ID)
+ pHlp->pfnPrintf(pHlp, "aRenderTargets[%s/%u] = %#x (%d)\n",
+ i < RT_ELEMENTS(g_apszRenderTargets) ? g_apszRenderTargets[i] : "UNKNOWN", i,
+ pContext->state.aRenderTargets[i], pContext->state.aRenderTargets[i]);
+
+ pHlp->pfnPrintf(pHlp, "RectScissor: (x,y,cx,cy)=(%u,%u,%u,%u)\n",
+ pContext->state.RectViewPort.x, pContext->state.RectViewPort.y,
+ pContext->state.RectViewPort.w, pContext->state.RectViewPort.h);
+ pHlp->pfnPrintf(pHlp, "zRange: (min,max)=(" FLOAT_FMT_STR ", " FLOAT_FMT_STR ")\n",
+ FLOAT_FMT_ARGS(pContext->state.zRange.min),
+ FLOAT_FMT_ARGS(pContext->state.zRange.max));
+ pHlp->pfnPrintf(pHlp, "fUpdateFlags: %#x\n", pContext->state.u32UpdateFlags);
+ pHlp->pfnPrintf(pHlp, "shidPixel: %#x (%d)\n", pContext->state.shidPixel, pContext->state.shidPixel);
+ pHlp->pfnPrintf(pHlp, "shidVertex: %#x (%d)\n", pContext->state.shidVertex, pContext->state.shidVertex);
+
+ for (uint32_t iWhich = 0; iWhich < 2; iWhich++)
+ {
+ uint32_t cConsts = iWhich == 0 ? pContext->state.cPixelShaderConst : pContext->state.cVertexShaderConst;
+ PVMSVGASHADERCONST paConsts = iWhich == 0 ? pContext->state.paPixelShaderConst : pContext->state.paVertexShaderConst;
+ const char *pszName = iWhich ? "paPixelShaderConst" : "paVertexShaderConst";
+
+ for (uint32_t i = 0; i < cConsts; i++)
+ if (paConsts[i].fValid)
+ {
+ if (paConsts[i].ctype == SVGA3D_CONST_TYPE_FLOAT)
+ pHlp->pfnPrintf(pHlp, "%s[%#x(%u)] = [" FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR ", " FLOAT_FMT_STR "] ctype=FLOAT\n",
+ pszName, i, i,
+ FLOAT_FMT_ARGS(paConsts[i].value[0]), FLOAT_FMT_ARGS(paConsts[i].value[1]),
+ FLOAT_FMT_ARGS(paConsts[i].value[2]), FLOAT_FMT_ARGS(paConsts[i].value[3]));
+ else
+ pHlp->pfnPrintf(pHlp, "%s[%#x(%u)] = [%#x, %#x, %#x, %#x] ctype=%s\n",
+ pszName, i, i,
+ paConsts[i].value[0], paConsts[i].value[1],
+ paConsts[i].value[2], paConsts[i].value[3],
+ paConsts[i].ctype == SVGA3D_CONST_TYPE_INT ? "INT"
+ : paConsts[i].ctype == SVGA3D_CONST_TYPE_BOOL ? "BOOL" : "UNKNOWN");
+ }
+ }
+
+ for (uint32_t iWhich = 0; iWhich < 2; iWhich++)
+ {
+ uint32_t cShaders = iWhich == 0 ? pContext->cPixelShaders : pContext->cVertexShaders;
+ PVMSVGA3DSHADER paShaders = iWhich == 0 ? pContext->paPixelShader : pContext->paVertexShader;
+ const char *pszName = iWhich == 0 ? "paPixelShaders" : "paVertexShaders";
+ for (uint32_t i = 0; i < cShaders; i++)
+ if (paShaders[i].id == i)
+ {
+ pHlp->pfnPrintf(pHlp, "%s[%u]: id=%#x cid=%#x type=%s(%d) cbData=%#x pvData=%p\n",
+ pszName, i,
+ paShaders[i].id,
+ paShaders[i].cid,
+ paShaders[i].type == SVGA3D_SHADERTYPE_VS ? "VS"
+ : paShaders[i].type == SVGA3D_SHADERTYPE_PS ? "PS" : "UNKNOWN",
+ paShaders[i].type,
+ paShaders[i].cbData,
+ paShaders[i].pShaderProgram);
+ }
+ }
+}
+
+
+void vmsvga3dInfoContextWorker(PVGASTATE pThis, PCDBGFINFOHLP pHlp, uint32_t cid, bool fVerbose)
+{
+ /* Warning! This code is currently racing papContexts reallocation! */
+ /* Warning! This code is currently racing papContexts reallocation! */
+ /* Warning! This code is currently racing papContexts reallocation! */
+ VMSVGA3DSTATE volatile *pState = pThis->svga.p3dState;
+ if (pState)
+ {
+ /*
+ * Deal with a specific request first.
+ */
+ if (cid != UINT32_MAX)
+ {
+ if (cid < pState->cContexts)
+ {
+ PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+ if (pContext && pContext->id == cid)
+ {
+ vmsvga3dInfoContextWorkerOne(pHlp, pContext, fVerbose);
+ return;
+ }
+ }
+#ifdef VMSVGA3D_OPENGL
+ else if ( cid == VMSVGA3D_SHARED_CTX_ID
+ && pState->SharedCtx.id == cid)
+ {
+ vmsvga3dInfoContextWorkerOne(pHlp, &((PVMSVGA3DSTATE)pState)->SharedCtx, fVerbose);
+ return;
+ }
+#endif
+ pHlp->pfnPrintf(pHlp, "Context ID %#x not found.\n", cid);
+ }
+ else
+ {
+#ifdef VMSVGA3D_OPENGL
+ /*
+ * Dump the shared context.
+ */
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ {
+ pHlp->pfnPrintf(pHlp, "Shared context:\n");
+ vmsvga3dInfoContextWorkerOne(pHlp, &((PVMSVGA3DSTATE)pState)->SharedCtx, fVerbose);
+ }
+#endif
+
+ /*
+ * Dump the per-screen contexts.
+ */
+ /** @todo multi screen */
+
+ /*
+ * Dump all.
+ */
+ uint32_t cContexts = pState->cContexts;
+ pHlp->pfnPrintf(pHlp, "cContexts=%d\n", cContexts);
+ for (cid = 0; cid < cContexts; cid++)
+ {
+ PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+ if (pContext && pContext->id == cid)
+ {
+ pHlp->pfnPrintf(pHlp, "\n");
+ vmsvga3dInfoContextWorkerOne(pHlp, pContext, fVerbose);
+ }
+ }
+ }
+ }
+}
+
+
+#ifdef VMSVGA3D_DIRECT3D
+/**
+ * Release all shared surface objects.
+ */
+static DECLCALLBACK(int) vmsvga3dInfoSharedObjectCallback(PAVLU32NODECORE pNode, void *pvUser)
+{
+ PVMSVGA3DSHAREDSURFACE pSharedSurface = (PVMSVGA3DSHAREDSURFACE)pNode;
+ PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvUser;
+
+ pHlp->pfnPrintf(pHlp, "Shared surface: %#x pv=%p\n", pSharedSurface->Core.Key, pSharedSurface->u.pCubeTexture);
+
+ return 0;
+}
+#endif /* VMSVGA3D_DIRECT3D */
+
+
+static void vmsvga3dInfoSurfaceWorkerOne(PCDBGFINFOHLP pHlp, PVMSVGA3DSURFACE pSurface,
+ bool fVerbose, uint32_t cxAscii, bool fInvY)
+{
+ char szTmp[128];
+
+ pHlp->pfnPrintf(pHlp, "*** VMSVGA 3d surface %#x (%d)%s ***\n", pSurface->id, pSurface->id, pSurface->fDirty ? " - dirty" : "");
+#ifdef VMSVGA3D_OPENGL
+ pHlp->pfnPrintf(pHlp, "idWeakContextAssociation: %#x\n", pSurface->idWeakContextAssociation);
+#else
+ pHlp->pfnPrintf(pHlp, "idAssociatedContext: %#x\n", pSurface->idAssociatedContext);
+#endif
+ pHlp->pfnPrintf(pHlp, "Format: %s\n",
+ vmsvgaFormatEnumValueEx(szTmp, sizeof(szTmp), NULL, (int)pSurface->format, false, &g_SVGA3dSurfaceFormat2String));
+ pHlp->pfnPrintf(pHlp, "Flags: %#x", pSurface->flags);
+ vmsvga3dInfoU32Flags(pHlp, pSurface->flags, "SVGA3D_SURFACE_", g_aSvga3DSurfaceFlags, RT_ELEMENTS(g_aSvga3DSurfaceFlags));
+ pHlp->pfnPrintf(pHlp, "\n");
+ if (pSurface->cFaces == 0)
+ pHlp->pfnPrintf(pHlp, "Faces: %u\n", pSurface->cFaces);
+ for (uint32_t iFace = 0; iFace < pSurface->cFaces; iFace++)
+ {
+ Assert(pSurface->faces[iFace].numMipLevels <= pSurface->faces[0].numMipLevels);
+ if (pSurface->faces[iFace].numMipLevels == 0)
+ pHlp->pfnPrintf(pHlp, "Faces[%u] Mipmap levels: %u\n", iFace, pSurface->faces[iFace].numMipLevels);
+
+ uint32_t iMipmap = iFace * pSurface->faces[0].numMipLevels;
+ for (uint32_t iLevel = 0; iLevel < pSurface->faces[iFace].numMipLevels; iLevel++, iMipmap++)
+ {
+ pHlp->pfnPrintf(pHlp, "Face #%u, mipmap #%u[%u]:%s cx=%u, cy=%u, cz=%u, cbSurface=%#x, cbPitch=%#x",
+ iFace, iLevel, iMipmap, iMipmap < 10 ? " " : "",
+ pSurface->pMipmapLevels[iMipmap].size.width,
+ pSurface->pMipmapLevels[iMipmap].size.height,
+ pSurface->pMipmapLevels[iMipmap].size.depth,
+ pSurface->pMipmapLevels[iMipmap].cbSurface,
+ pSurface->pMipmapLevels[iMipmap].cbSurfacePitch);
+ if (pSurface->pMipmapLevels[iMipmap].pSurfaceData)
+ pHlp->pfnPrintf(pHlp, " pvData=%p", pSurface->pMipmapLevels[iMipmap].pSurfaceData);
+ if (pSurface->pMipmapLevels[iMipmap].fDirty)
+ pHlp->pfnPrintf(pHlp, " dirty");
+ pHlp->pfnPrintf(pHlp, "\n");
+ }
+ }
+
+ pHlp->pfnPrintf(pHlp, "cbBlock: %u (%#x)\n", pSurface->cbBlock, pSurface->cbBlock);
+ pHlp->pfnPrintf(pHlp, "Multi-sample count: %u\n", pSurface->multiSampleCount);
+ pHlp->pfnPrintf(pHlp, "Autogen filter: %s\n",
+ vmsvgaFormatEnumValue(szTmp, sizeof(szTmp), NULL, pSurface->autogenFilter,
+ "SVGA3D_TEX_FILTER_", g_apszTexureFilters, RT_ELEMENTS(g_apszTexureFilters)));
+
+#ifdef VMSVGA3D_DIRECT3D
+ pHlp->pfnPrintf(pHlp, "formatD3D: %s\n",
+ vmsvgaFormatEnumValueEx(szTmp, sizeof(szTmp), NULL, pSurface->formatD3D, true, &g_D3DFormat2String));
+ pHlp->pfnPrintf(pHlp, "fUsageD3D: %#x", pSurface->fUsageD3D);
+ vmsvga3dInfoU32Flags(pHlp, pSurface->fUsageD3D, "D3DUSAGE_", g_aD3DUsageFlags, RT_ELEMENTS(g_aD3DUsageFlags));
+ pHlp->pfnPrintf(pHlp, "\n");
+ pHlp->pfnPrintf(pHlp, "multiSampleTypeD3D: %s\n",
+ vmsvgaFormatEnumValueEx(szTmp, sizeof(szTmp), NULL, pSurface->multiSampleTypeD3D,
+ true, &g_D3DMultiSampleType2String));
+ if (pSurface->hSharedObject != NULL)
+ pHlp->pfnPrintf(pHlp, "hSharedObject: %p\n", pSurface->hSharedObject);
+ if (pSurface->pQuery)
+ pHlp->pfnPrintf(pHlp, "pQuery: %p\n", pSurface->pQuery);
+ if (pSurface->u.pSurface)
+ pHlp->pfnPrintf(pHlp, "u.pXxxx: %p\n", pSurface->u.pSurface);
+ if (pSurface->bounce.pTexture)
+ pHlp->pfnPrintf(pHlp, "bounce.pXxxx: %p\n", pSurface->bounce.pTexture);
+ RTAvlU32DoWithAll(&pSurface->pSharedObjectTree, true /*fFromLeft*/, vmsvga3dInfoSharedObjectCallback, (void *)pHlp);
+ pHlp->pfnPrintf(pHlp, "fStencilAsTexture: %RTbool\n", pSurface->fStencilAsTexture);
+
+#elif defined(VMSVGA3D_OPENGL)
+ /** @todo */
+#else
+# error "Build config error."
+#endif
+
+ if (fVerbose)
+ for (uint32_t iFace = 0; iFace < pSurface->cFaces; iFace++)
+ {
+ uint32_t iMipmap = iFace * pSurface->faces[0].numMipLevels;
+ for (uint32_t iLevel = 0; iLevel < pSurface->faces[iFace].numMipLevels; iLevel++, iMipmap++)
+ if (pSurface->pMipmapLevels[iMipmap].pSurfaceData)
+ {
+ if ( ASMMemIsAll8(pSurface->pMipmapLevels[iMipmap].pSurfaceData,
+ pSurface->pMipmapLevels[iMipmap].cbSurface, 0) == NULL)
+ pHlp->pfnPrintf(pHlp, "--- Face #%u, mipmap #%u[%u]: all zeros ---\n", iFace, iLevel, iMipmap);
+ else
+ {
+ pHlp->pfnPrintf(pHlp, "--- Face #%u, mipmap #%u[%u]: cx=%u, cy=%u, cz=%u ---\n",
+ iFace, iLevel, iMipmap,
+ pSurface->pMipmapLevels[iMipmap].size.width,
+ pSurface->pMipmapLevels[iMipmap].size.height,
+ pSurface->pMipmapLevels[iMipmap].size.depth);
+ vmsvga3dAsciiPrint(vmsvga3dAsciiPrintlnInfo, (void *)pHlp,
+ pSurface->pMipmapLevels[iMipmap].pSurfaceData,
+ pSurface->pMipmapLevels[iMipmap].cbSurface,
+ pSurface->pMipmapLevels[iMipmap].size.width,
+ pSurface->pMipmapLevels[iMipmap].size.height,
+ pSurface->pMipmapLevels[iMipmap].cbSurfacePitch,
+ pSurface->format,
+ fInvY,
+ cxAscii, cxAscii * 3 / 4);
+ }
+ }
+ }
+}
+
+
+void vmsvga3dInfoSurfaceWorker(PVGASTATE pThis, PCDBGFINFOHLP pHlp, uint32_t sid, bool fVerbose, uint32_t cxAscii, bool fInvY)
+{
+ /* Warning! This code is currently racing papSurfaces reallocation! */
+ /* Warning! This code is currently racing papSurfaces reallocation! */
+ /* Warning! This code is currently racing papSurfaces reallocation! */
+ VMSVGA3DSTATE volatile *pState = pThis->svga.p3dState;
+ if (pState)
+ {
+ /*
+ * Deal with a specific request first.
+ */
+ if (sid != UINT32_MAX)
+ {
+ if (sid < pState->cSurfaces)
+ {
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ if (pSurface && pSurface->id == sid)
+ {
+ if (fVerbose)
+ vmsvga3dSurfaceUpdateHeapBuffersOnFifoThread(pThis, sid);
+ vmsvga3dInfoSurfaceWorkerOne(pHlp, pSurface, fVerbose, cxAscii, fInvY);
+ return;
+ }
+ }
+ pHlp->pfnPrintf(pHlp, "Surface ID %#x not found.\n", sid);
+ }
+ else
+ {
+ /*
+ * Dump all.
+ */
+ if (fVerbose)
+ vmsvga3dSurfaceUpdateHeapBuffersOnFifoThread(pThis, UINT32_MAX);
+ uint32_t cSurfaces = pState->cSurfaces;
+ pHlp->pfnPrintf(pHlp, "cSurfaces=%d\n", cSurfaces);
+ for (sid = 0; sid < cSurfaces; sid++)
+ {
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ if (pSurface && pSurface->id == sid)
+ {
+ pHlp->pfnPrintf(pHlp, "\n");
+ vmsvga3dInfoSurfaceWorkerOne(pHlp, pSurface, fVerbose, cxAscii, fInvY);
+ }
+ }
+ }
+ }
+
+}
+
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-internal.h b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-internal.h
new file mode 100644
index 0000000..332dd51
--- /dev/null
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-internal.h
@@ -0,0 +1,1062 @@
+/* $Id: DevVGA-SVGA3d-internal.h $ */
+/** @file
+ * DevVMWare - VMWare SVGA device - 3D part, internal header.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___DevVGA_SVGA3d_internal_h
+#define ___DevVGA_SVGA3d_internal_h
+
+/*
+ * Assert sane compilation environment.
+ */
+#ifndef IN_RING3
+# error "VMSVGA3D_INCL_INTERNALS is only for ring-3 code"
+#endif
+#ifdef VMSVGA3D_OPENGL
+# ifdef VMSVGA3D_DIRECT3D
+# error "Both VMSVGA3D_DIRECT3D and VMSVGA3D_OPENGL cannot be defined at the same time."
+# endif
+#elif !defined(VMSVGA3D_DIRECT3D)
+# error "Either VMSVGA3D_OPENGL or VMSVGA3D_DIRECT3D must be defined."
+#endif
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "DevVGA-SVGA3d.h"
+
+#ifdef RT_OS_WINDOWS
+# include <Windows.h>
+# ifdef VMSVGA3D_DIRECT3D
+# include <d3d9.h>
+# include <iprt/avl.h>
+# else
+# include <GL/gl.h>
+# include "vmsvga_glext/wglext.h"
+# endif
+
+#elif defined(RT_OS_DARWIN)
+# include <OpenGL/OpenGL.h>
+# include <OpenGL/gl3.h>
+# include <OpenGL/gl3ext.h>
+# define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
+# include <OpenGL/gl.h>
+# include <OpenGL/glext.h>
+# include "DevVGA-SVGA3d-cocoa.h"
+/* work around conflicting definition of GLhandleARB in VMware's glext.h */
+//#define GL_ARB_shader_objects
+// HACK
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+# define GL_RGBA_S3TC 0x83A2
+# define GL_ALPHA8_EXT 0x803c
+# define GL_LUMINANCE8_EXT 0x8040
+# define GL_LUMINANCE16_EXT 0x8042
+# define GL_LUMINANCE4_ALPHA4_EXT 0x8043
+# define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+# define GL_INT_2_10_10_10_REV 0x8D9F
+
+#else
+# include <X11/Xlib.h>
+# include <X11/Xatom.h>
+# include <GL/gl.h>
+# include <GL/glx.h>
+# include <GL/glext.h>
+# define VBOX_VMSVGA3D_GL_HACK_LEVEL 0x103
+#endif
+
+#include "vmsvga/svga3d_shaderdefs.h"
+#ifdef VMSVGA3D_OPENGL
+# include "vmsvga_glext/glext.h"
+# include "shaderlib/shaderlib.h"
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef VMSVGA3D_OPENGL
+/** OpenGL: Create a dedicated context for handling surfaces in, thus
+ * avoiding orphaned surfaces after context destruction.
+ *
+ * This cures, for instance, an assertion on fedora 21 that happens in
+ * vmsvga3dSurfaceStretchBlt if the login screen and the desktop has different
+ * sizes. The context of the login screen seems to have just been destroyed
+ * earlier and I believe the driver/X/whoever is attemting to strech the old
+ * screen content onto the new sized screen.
+ *
+ * @remarks This probably comes at a slight preformance expense, as we currently
+ * switches context when setting up the surface the first time. Not sure
+ * if we really need to, but as this is an experiment, I'm playing it safe.
+ * @remarks The define has been made default, thus should no longer be used.
+ */
+# define VMSVGA3D_OGL_WITH_SHARED_CTX
+/** Fake surface ID for the shared context. */
+# define VMSVGA3D_SHARED_CTX_ID UINT32_C(0xffffeeee)
+
+/** @def VBOX_VMSVGA3D_GL_HACK_LEVEL
+ * Turns out that on Linux gl.h may often define the first 2-4 OpenGL versions
+ * worth of extensions, but missing out on a function pointer of fifteen. This
+ * causes headache for us when we use the function pointers below. This hack
+ * changes the code to call the known problematic functions directly.
+ * The value is ((x)<<16 | (y)) where x and y are taken from the GL_VERSION_x_y.
+ */
+# ifndef VBOX_VMSVGA3D_GL_HACK_LEVEL
+# define VBOX_VMSVGA3D_GL_HACK_LEVEL 0
+# endif
+
+/** Invalid OpenGL ID. */
+# define OPENGL_INVALID_ID 0
+
+# define VMSVGA3D_CLEAR_CURRENT_CONTEXT(pState) \
+ do { (pState)->idActiveContext = OPENGL_INVALID_ID; } while (0)
+
+/** @def VMSVGA3D_SET_CURRENT_CONTEXT
+ * Makes sure the @a pContext is the active OpenGL context.
+ * @parm pState The VMSVGA3d state.
+ * @parm pContext The new context.
+ */
+# ifdef RT_OS_WINDOWS
+# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
+ do { \
+ if ((pState)->idActiveContext != (pContext)->id) \
+ { \
+ BOOL fMakeCurrentRc = wglMakeCurrent((pContext)->hdc, (pContext)->hglrc); \
+ Assert(fMakeCurrentRc == TRUE); \
+ LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
+ (pState)->idActiveContext = (pContext)->id; \
+ } \
+ } while (0)
+
+# elif defined(RT_OS_DARWIN)
+# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
+ do { \
+ if ((pState)->idActiveContext != (pContext)->id) \
+ { \
+ vmsvga3dCocoaViewMakeCurrentContext((pContext)->cocoaView, (pContext)->cocoaContext); \
+ LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
+ (pState)->idActiveContext = (pContext)->id; \
+ } \
+ } while (0)
+# else
+# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
+ do { \
+ if ((pState)->idActiveContext != (pContext)->id) \
+ { \
+ Bool fMakeCurrentRc = glXMakeCurrent((pState)->display, \
+ (pContext)->window, \
+ (pContext)->glxContext); \
+ Assert(fMakeCurrentRc == True); \
+ LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
+ (pState)->idActiveContext = (pContext)->id; \
+ } \
+ } while (0)
+# endif
+
+/** @def VMSVGA3D_CLEAR_GL_ERRORS
+ * Clears all pending OpenGL errors.
+ *
+ * If I understood this correctly, OpenGL maintains a bitmask internally and
+ * glGetError gets the next bit (clearing it) from the bitmap and translates it
+ * into a GL_XXX constant value which it then returns. A single OpenGL call can
+ * set more than one bit, and they stick around across calls, from what I
+ * understand.
+ *
+ * So in order to be able to use glGetError to check whether a function
+ * succeeded, we need to call glGetError until all error bits have been cleared.
+ * This macro does that (in all types of builds).
+ *
+ * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS
+ */
+# define VMSVGA3D_CLEAR_GL_ERRORS() \
+ do { \
+ if (RT_UNLIKELY(glGetError() != GL_NO_ERROR)) /* predict no errors pending */ \
+ { \
+ uint32_t iErrorClearingLoopsLeft = 64; \
+ while (glGetError() != GL_NO_ERROR && iErrorClearingLoopsLeft > 0) \
+ iErrorClearingLoopsLeft--; \
+ } \
+ } while (0)
+
+/** @def VMSVGA3D_GET_LAST_GL_ERROR
+ * Gets the last OpenGL error, stores it in a_pContext->lastError and returns
+ * it.
+ *
+ * @returns Same as glGetError.
+ * @param a_pContext The context to store the error in.
+ *
+ * @sa VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_GET_GL_ERROR(a_pContext) ((a_pContext)->lastError = glGetError())
+
+/** @def VMSVGA3D_GL_SUCCESS
+ * Checks whether VMSVGA3D_GET_LAST_GL_ERROR() return GL_NO_ERROR.
+ *
+ * Will call glGetError() and store the result in a_pContext->lastError.
+ * Will predict GL_NO_ERROR outcome.
+ *
+ * @returns True on success, false on error.
+ * @parm a_pContext The context to store the error in.
+ *
+ * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_GL_IS_SUCCESS(a_pContext) RT_LIKELY((((a_pContext)->lastError = glGetError()) == GL_NO_ERROR))
+
+/** @def VMSVGA3D_GL_COMPLAIN
+ * Complains about one or more OpenGL errors (first in a_pContext->lastError).
+ *
+ * Strict builds will trigger an assertion, while other builds will put the
+ * first few occurences in the release log.
+ *
+ * All GL errors will be cleared after invocation. Assumes lastError
+ * is an error, will not check for GL_NO_ERROR.
+ *
+ * @param a_pState The 3D state structure.
+ * @param a_pContext The context that holds the first error.
+ * @param a_LogRelDetails Argument list for LogRel or similar that describes
+ * the operation in greater detail.
+ *
+ * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS
+ */
+# ifdef VBOX_STRICT
+# define VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
+ do { \
+ AssertMsg((a_pState)->idActiveContext == (a_pContext)->id, \
+ ("idActiveContext=%#x id=%x\n", (a_pState)->idActiveContext, (a_pContext)->id)); \
+ RTAssertMsg2Weak a_LogRelDetails; \
+ GLenum iNextError; \
+ while ((iNextError = glGetError()) != GL_NO_ERROR) \
+ RTAssertMsg2Weak("next error: %#x\n", iNextError); \
+ AssertMsgFailed(("first error: %#x (idActiveContext=%#x)\n", (a_pContext)->lastError, (a_pContext)->id)); \
+ } while (0)
+# else
+# define VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
+ do { \
+ LogRelMax(32, ("VMSVGA3d: OpenGL error %#x (idActiveContext=%#x) on line %u ", (a_pContext)->lastError, (a_pContext)->id)); \
+ GLenum iNextError; \
+ while ((iNextError = glGetError()) != GL_NO_ERROR) \
+ LogRelMax(32, (" - also error %#x ", iNextError)); \
+ LogRelMax(32, a_LogRelDetails); \
+ } while (0)
+# endif
+
+/** @def VMSVGA3D_GL_GET_AND_COMPLAIN
+ * Combination of VMSVGA3D_GET_GL_ERROR and VMSVGA3D_GL_COMPLAIN, assuming that
+ * there is a pending error.
+ *
+ * @param a_pState The 3D state structure.
+ * @param a_pContext The context that holds the first error.
+ * @param a_LogRelDetails Argument list for LogRel or similar that describes
+ * the operation in greater detail.
+ *
+ * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_GL_GET_AND_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
+ do { \
+ VMSVGA3D_GET_GL_ERROR(a_pContext); \
+ VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails); \
+ } while (0)
+
+/** @def VMSVGA3D_GL_ASSERT_SUCCESS
+ * Asserts that VMSVGA3D_GL_IS_SUCCESS is true, complains if not.
+ *
+ * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
+ * logging in non-strict builds.
+ *
+ * @param a_pState The 3D state structure.
+ * @param a_pContext The context that holds the first error.
+ * @param a_LogRelDetails Argument list for LogRel or similar that describes
+ * the operation in greater detail.
+ *
+ * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_GL_ASSERT_SUCCESS(a_pState, a_pContext, a_LogRelDetails) \
+ if (VMSVGA3D_GL_IS_SUCCESS(a_pContext)) \
+ { /* likely */ } \
+ else do { \
+ VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails); \
+ } while (0)
+
+/** @def VMSVGA3D_ASSERT_GL_CALL_EX
+ * Executes the specified OpenGL API call and asserts that it succeeded, variant
+ * with extra logging flexibility.
+ *
+ * ASSUMES no GL errors pending prior to invocation - caller should use
+ * VMSVGA3D_CLEAR_GL_ERRORS if uncertain.
+ *
+ * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
+ * logging in non-strict builds.
+ *
+ * @param a_GlCall Expression making an OpenGL call.
+ * @param a_pState The 3D state structure.
+ * @param a_pContext The context that holds the first error.
+ * @param a_LogRelDetails Argument list for LogRel or similar that describes
+ * the operation in greater detail.
+ *
+ * @sa VMSVGA3D_ASSERT_GL_CALL, VMSVGA3D_GL_ASSERT_SUCCESS,
+ * VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_ASSERT_GL_CALL_EX(a_GlCall, a_pState, a_pContext, a_LogRelDetails) \
+ do { \
+ (a_GlCall); \
+ VMSVGA3D_GL_ASSERT_SUCCESS(a_pState, a_pContext, a_LogRelDetails); \
+ } while (0)
+
+/** @def VMSVGA3D_ASSERT_GL_CALL
+ * Executes the specified OpenGL API call and asserts that it succeeded.
+ *
+ * ASSUMES no GL errors pending prior to invocation - caller should use
+ * VMSVGA3D_CLEAR_GL_ERRORS if uncertain.
+ *
+ * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
+ * logging in non-strict builds.
+ *
+ * @param a_GlCall Expression making an OpenGL call.
+ * @param a_pState The 3D state structure.
+ * @param a_pContext The context that holds the first error.
+ *
+ * @sa VMSVGA3D_ASSERT_GL_CALL_EX, VMSVGA3D_GL_ASSERT_SUCCESS,
+ * VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
+ */
+# define VMSVGA3D_ASSERT_GL_CALL(a_GlCall, a_pState, a_pContext) \
+ VMSVGA3D_ASSERT_GL_CALL_EX(a_GlCall, a_pState, a_pContext, ("%s\n", #a_GlCall))
+
+
+/** @def VMSVGA3D_CHECK_LAST_ERROR
+ * Checks that the last OpenGL error code indicates success.
+ *
+ * Will assert and return VERR_INTERNAL_ERROR in strict builds, in other
+ * builds it will do nothing and is a NOOP.
+ *
+ * @parm pState The VMSVGA3d state.
+ * @parm pContext The context.
+ *
+ * @todo Replace with proper error handling, it's crazy to return
+ * VERR_INTERNAL_ERROR in strict builds and just barge on ahead in
+ * release builds.
+ */
+# ifdef VBOX_STRICT
+# define VMSVGA3D_CHECK_LAST_ERROR(pState, pContext) do { \
+ Assert((pState)->idActiveContext == (pContext)->id); \
+ (pContext)->lastError = glGetError(); \
+ AssertMsgReturn((pContext)->lastError == GL_NO_ERROR, \
+ ("%s (%d): last error 0x%x\n", __FUNCTION__, __LINE__, (pContext)->lastError), \
+ VERR_INTERNAL_ERROR); \
+ } while (0)
+# else
+# define VMSVGA3D_CHECK_LAST_ERROR(pState, pContext) do { } while (0)
+# endif
+
+/** @def VMSVGA3D_CHECK_LAST_ERROR_WARN
+ * Checks that the last OpenGL error code indicates success.
+ *
+ * Will assert in strict builds, otherwise it's a NOOP.
+ *
+ * @parm pState The VMSVGA3d state.
+ * @parm pContext The new context.
+ */
+# ifdef VBOX_STRICT
+# define VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext) do { \
+ Assert((pState)->idActiveContext == (pContext)->id); \
+ (pContext)->lastError = glGetError(); \
+ AssertMsg((pContext)->lastError == GL_NO_ERROR, ("%s (%d): last error 0x%x\n", __FUNCTION__, __LINE__, (pContext)->lastError)); \
+ } while (0)
+# else
+# define VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext) do { } while (0)
+# endif
+
+#endif /* VMSVGA3D_OPENGL */
+
+#ifdef VMSVGA3D_DIRECT3D
+/* Enable to use Wine to convert D3D to opengl */
+//#define VBOX_VMSVGA3D_WITH_WINE_OPENGL
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Mipmap level.
+ */
+typedef struct VMSVGA3DMIPMAPLEVEL
+{
+ /** The mipmap size. */
+ SVGA3dSize size;
+ /** The size (in bytes) of the mimap data when using the format the surface was
+ * defined with. */
+ uint32_t cbSurface;
+ /** The scanline/pitch size in bytes. */
+ uint32_t cbSurfacePitch;
+ /** Pointer to the mipmap bytes (cbSurface). Often NULL. If the surface has
+ * been realized in hardware, this may be outdated. */
+ void *pSurfaceData;
+ /** Set if pvSurfaceData contains data not realized in hardware or pushed to the
+ * hardware surface yet. */
+ bool fDirty;
+} VMSVGA3DMIPMAPLEVEL;
+/** Pointer to a mipmap level. */
+typedef VMSVGA3DMIPMAPLEVEL *PVMSVGA3DMIPMAPLEVEL;
+
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGA3DMIPMAPLEVEL structure.
+ */
+static SSMFIELD const g_aVMSVGA3DMIPMAPLEVELFields[] =
+{
+ SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, size),
+ SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurface),
+ SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurfacePitch),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DMIPMAPLEVEL, pSurfaceData),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DMIPMAPLEVEL, fDirty),
+ SSMFIELD_ENTRY_TERM()
+};
+#endif
+
+typedef struct VMSVGATRANSFORMSTATE
+{
+ bool fValid;
+ float matrix[16];
+} VMSVGATRANSFORMSTATE;
+typedef VMSVGATRANSFORMSTATE *PVMSVGATRANSFORMSTATE;
+
+typedef struct VMSVGAMATERIALSTATE
+{
+ bool fValid;
+ SVGA3dMaterial material;
+} VMSVGAMATERIALSTATE;
+typedef VMSVGAMATERIALSTATE *PVMSVGAMATERIALSTATE;
+
+typedef struct VMSVGACLIPPLANESTATE
+{
+ bool fValid;
+ float plane[4];
+} VMSVGACLIPPLANESTATE;
+typedef VMSVGACLIPPLANESTATE *PVMSVGACLIPPLANESTATE;
+
+typedef struct VMSVGALIGHTSTATE
+{
+ bool fEnabled;
+ bool fValidData;
+ SVGA3dLightData data;
+} VMSVGALIGHTSTATE;
+typedef VMSVGALIGHTSTATE *PVMSVGALIGHTSTATE;
+
+typedef struct VMSVGASHADERCONST
+{
+ bool fValid;
+ SVGA3dShaderConstType ctype;
+ uint32_t value[4];
+} VMSVGASHADERCONST;
+typedef VMSVGASHADERCONST *PVMSVGASHADERCONST;
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGASHADERCONST structure.
+ */
+static SSMFIELD const g_aVMSVGASHADERCONSTFields[] =
+{
+ SSMFIELD_ENTRY( VMSVGASHADERCONST, fValid),
+ SSMFIELD_ENTRY( VMSVGASHADERCONST, ctype),
+ SSMFIELD_ENTRY( VMSVGASHADERCONST, value),
+ SSMFIELD_ENTRY_TERM()
+};
+#endif
+
+#ifdef VMSVGA3D_DIRECT3D
+/**
+ *
+ */
+typedef struct
+{
+ /** Key is context id. */
+ AVLU32NODECORE Core;
+ union
+ {
+ IDirect3DSurface9 *pSurface;
+ IDirect3DTexture9 *pTexture;
+ IDirect3DCubeTexture9 *pCubeTexture;
+ } u;
+} VMSVGA3DSHAREDSURFACE;
+typedef VMSVGA3DSHAREDSURFACE *PVMSVGA3DSHAREDSURFACE;
+#endif /* VMSVGA3D_DIRECT3D */
+
+/**
+ * VMSVGA3d surface.
+ */
+typedef struct VMSVGA3DSURFACE
+{
+ uint32_t id;
+#ifdef VMSVGA3D_OPENGL
+ uint32_t idWeakContextAssociation;
+#else
+ uint32_t idAssociatedContext;
+#endif
+ uint32_t flags;
+ SVGA3dSurfaceFormat format;
+#ifdef VMSVGA3D_OPENGL
+ GLint internalFormatGL;
+ GLint formatGL;
+ GLint typeGL;
+ union
+ {
+ GLuint texture;
+ GLuint buffer;
+ GLuint renderbuffer;
+ } oglId;
+#endif
+ SVGA3dSurfaceFace faces[SVGA3D_MAX_SURFACE_FACES];
+ uint32_t cFaces;
+ PVMSVGA3DMIPMAPLEVEL pMipmapLevels;
+ uint32_t multiSampleCount;
+ SVGA3dTextureFilter autogenFilter;
+#ifdef VMSVGA3D_DIRECT3D
+ D3DFORMAT formatD3D;
+ DWORD fUsageD3D;
+ D3DMULTISAMPLE_TYPE multiSampleTypeD3D;
+#endif
+
+ uint32_t cbBlock; /* block/pixel size in bytes */
+ /* Dirty state; surface was manually updated. */
+ bool fDirty;
+
+#ifdef VMSVGA3D_DIRECT3D
+ /* Handle for shared objects (currently only textures & render targets). */
+ HANDLE hSharedObject;
+ /** Event query inserted after each GPU operation that updates or uses this surface. */
+ IDirect3DQuery9 *pQuery;
+ union
+ {
+ IDirect3DSurface9 *pSurface;
+ IDirect3DCubeTexture9 *pCubeTexture;
+ IDirect3DIndexBuffer9 *pIndexBuffer;
+ IDirect3DTexture9 *pTexture;
+ IDirect3DVertexBuffer9 *pVertexBuffer;
+ } u;
+ union
+ {
+ IDirect3DTexture9 *pTexture;
+ } bounce;
+ /** AVL tree containing VMSVGA3DSHAREDSURFACE structures. */
+ AVLU32TREE pSharedObjectTree;
+ bool fStencilAsTexture;
+#endif
+} VMSVGA3DSURFACE;
+/** Pointer to a 3d surface. */
+typedef VMSVGA3DSURFACE *PVMSVGA3DSURFACE;
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGA3DSURFACE structure.
+ */
+static SSMFIELD const g_aVMSVGA3DSURFACEFields[] =
+{
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, id),
+# ifdef VMSVGA3D_OPENGL
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, idWeakContextAssociation),
+# else
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, idAssociatedContext),
+# endif
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, flags),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, format),
+# ifdef VMSVGA3D_OPENGL
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, internalFormatGL),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, formatGL),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, typeGL),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, id),
+# endif
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, faces),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, cFaces),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, pMipmapLevels),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, multiSampleCount),
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, autogenFilter),
+# ifdef VMSVGA3D_DIRECT3D
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, format), /** @todo format duplicated. */
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, formatD3D),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fUsageD3D),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, multiSampleTypeD3D),
+# endif
+ SSMFIELD_ENTRY( VMSVGA3DSURFACE, cbBlock),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fDirty),
+# ifdef VMSVGA3D_DIRECT3D
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, hSharedObject),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, pQuery),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, u.pSurface),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, bounce.pTexture),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, pSharedObjectTree),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fStencilAsTexture),
+# endif
+ SSMFIELD_ENTRY_TERM()
+};
+#endif
+
+/** Mask we frequently apply to VMSVGA3DSURFACE::flags for decing what kind
+ * of surface we're dealing. */
+#define VMSVGA3D_SURFACE_HINT_SWITCH_MASK \
+ ( SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER \
+ | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET \
+ | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP )
+
+/** @def VMSVGA3DSURFACE_HAS_HW_SURFACE
+ * Checks whether the surface has a host hardware/library surface.
+ * @returns true/false
+ * @param a_pSurface The VMSVGA3d surface.
+ */
+#ifdef VMSVGA3D_DIRECT3D
+# define VMSVGA3DSURFACE_HAS_HW_SURFACE(a_pSurface) ((a_pSurface)->u.pSurface != NULL)
+#else
+# define VMSVGA3DSURFACE_HAS_HW_SURFACE(a_pSurface) ((a_pSurface)->oglId.texture != OPENGL_INVALID_ID)
+#endif
+
+
+
+typedef struct VMSVGA3DSHADER
+{
+ uint32_t id;
+ uint32_t cid;
+ SVGA3dShaderType type;
+ uint32_t cbData;
+ void *pShaderProgram;
+ union
+ {
+#ifdef VMSVGA3D_DIRECT3D
+ IDirect3DVertexShader9 *pVertexShader;
+ IDirect3DPixelShader9 *pPixelShader;
+#else
+ void *pVertexShader;
+ void *pPixelShader;
+#endif
+ void *pv;
+ } u;
+} VMSVGA3DSHADER;
+typedef VMSVGA3DSHADER *PVMSVGA3DSHADER;
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGA3DSHADER structure.
+ */
+static SSMFIELD const g_aVMSVGA3DSHADERFields[] =
+{
+ SSMFIELD_ENTRY( VMSVGA3DSHADER, id),
+ SSMFIELD_ENTRY( VMSVGA3DSHADER, cid),
+ SSMFIELD_ENTRY( VMSVGA3DSHADER, type),
+ SSMFIELD_ENTRY( VMSVGA3DSHADER, cbData),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, pShaderProgram),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, u.pv),
+ SSMFIELD_ENTRY_TERM()
+};
+#endif
+
+/** @name VMSVGA3D_UPDATE_XXX - ...
+ * @{ */
+#define VMSVGA3D_UPDATE_SCISSORRECT RT_BIT_32(0)
+#define VMSVGA3D_UPDATE_ZRANGE RT_BIT_32(1)
+#define VMSVGA3D_UPDATE_VIEWPORT RT_BIT_32(2)
+#define VMSVGA3D_UPDATE_VERTEXSHADER RT_BIT_32(3)
+#define VMSVGA3D_UPDATE_PIXELSHADER RT_BIT_32(4)
+#define VMSVGA3D_UPDATE_TRANSFORM RT_BIT_32(5)
+#define VMSVGA3D_UPDATE_MATERIAL RT_BIT_32(6)
+/** @} */
+
+/**
+ * VMSVGA3d context.
+ */
+typedef struct VMSVGA3DCONTEXT
+{
+ uint32_t id;
+#ifdef RT_OS_WINDOWS
+# ifdef VMSVGA3D_DIRECT3D
+# ifdef VBOX_VMSVGA3D_WITH_WINE_OPENGL
+ IDirect3DDevice9 *pDevice;
+# else
+ IDirect3DDevice9Ex *pDevice;
+# endif
+# else
+ /* Device context of the context window. */
+ HDC hdc;
+ /* OpenGL rendering context handle. */
+ HGLRC hglrc;
+# endif
+ /* Device context window handle. */
+ HWND hwnd;
+#elif defined(RT_OS_DARWIN)
+ /* OpenGL rendering context */
+ NativeNSOpenGLContextRef cocoaContext;
+ NativeNSViewRef cocoaView;
+ bool fOtherProfile;
+#else
+ /** XGL rendering context handle */
+ GLXContext glxContext;
+ /** Device context window handle */
+ Window window;
+ /** flag whether the window is mapped (=visible) */
+ bool fMapped;
+#endif
+
+#ifdef VMSVGA3D_OPENGL
+ /* Framebuffer object associated with this context. */
+ GLuint idFramebuffer;
+ /* Read and draw framebuffer objects for various operations. */
+ GLuint idReadFramebuffer;
+ GLuint idDrawFramebuffer;
+ /* Last GL error recorded. */
+ GLenum lastError;
+ void *pShaderContext;
+#endif
+
+ /* Current active render target (if any) */
+ uint32_t sidRenderTarget;
+ /* Current selected texture surfaces (if any) */
+ uint32_t aSidActiveTexture[SVGA3D_MAX_TEXTURE_STAGE];
+ /* Per context pixel and vertex shaders. */
+ uint32_t cPixelShaders;
+ PVMSVGA3DSHADER paPixelShader;
+ uint32_t cVertexShaders;
+ PVMSVGA3DSHADER paVertexShader;
+ /* Keep track of the internal state to be able to recreate the context properly (save/restore, window resize). */
+ struct
+ {
+ /** VMSVGA3D_UPDATE_XXX */
+ uint32_t u32UpdateFlags;
+
+ SVGA3dRenderState aRenderState[SVGA3D_RS_MAX];
+ SVGA3dTextureState aTextureState[SVGA3D_MAX_TEXTURE_STAGE][SVGA3D_TS_MAX];
+ VMSVGATRANSFORMSTATE aTransformState[SVGA3D_TRANSFORM_MAX];
+ VMSVGAMATERIALSTATE aMaterial[SVGA3D_FACE_MAX];
+ VMSVGACLIPPLANESTATE aClipPlane[SVGA3D_CLIPPLANE_MAX];
+ VMSVGALIGHTSTATE aLightData[SVGA3D_MAX_LIGHTS];
+
+ uint32_t aRenderTargets[SVGA3D_RT_MAX];
+ SVGA3dRect RectScissor;
+ SVGA3dRect RectViewPort;
+ SVGA3dZRange zRange;
+ uint32_t shidPixel;
+ uint32_t shidVertex;
+
+ uint32_t cPixelShaderConst;
+ PVMSVGASHADERCONST paPixelShaderConst;
+ uint32_t cVertexShaderConst;
+ PVMSVGASHADERCONST paVertexShaderConst;
+ } state;
+} VMSVGA3DCONTEXT;
+/** Pointer to a VMSVGA3d context. */
+typedef VMSVGA3DCONTEXT *PVMSVGA3DCONTEXT;
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGA3DCONTEXT structure.
+ */
+static SSMFIELD const g_aVMSVGA3DCONTEXTFields[] =
+{
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, id),
+
+# ifdef RT_OS_WINDOWS
+# ifdef VMSVGA3D_DIRECT3D
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, pDevice),
+# else
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hdc),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hglrc),
+# endif
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hwnd),
+# elif defined(RT_OS_DARWIN)
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, cocoaContext),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, cocoaView),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, fOtherProfile),
+# else
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, glxContext),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, window),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, fMapped),
+# endif
+
+#ifdef VMSVGA3D_OPENGL
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idFramebuffer),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idReadFramebuffer),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idDrawFramebuffer),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, lastError),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, pShaderContext),
+#endif
+
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, sidRenderTarget),
+ SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, aSidActiveTexture),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cPixelShaders),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paPixelShader),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cVertexShaders),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paVertexShader),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.u32UpdateFlags),
+
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderState),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTextureState),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTransformState),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aMaterial),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aClipPlane),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aLightData),
+
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderTargets),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectScissor),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectViewPort),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.zRange),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidPixel),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidVertex),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cPixelShaderConst),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paPixelShaderConst),
+ SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cVertexShaderConst),
+ SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paVertexShaderConst),
+ SSMFIELD_ENTRY_TERM()
+};
+#endif /* VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS */
+
+
+/**
+ * VMSVGA3d state data.
+ *
+ * Allocated on the heap and pointed to by VMSVGAState::p3dState.
+ */
+typedef struct VMSVGA3DSTATE
+{
+ /** The size of papContexts. */
+ uint32_t cContexts;
+ /** The size of papSurfaces. */
+ uint32_t cSurfaces;
+ /** Contexts indexed by ID. Grown as needed. */
+ PVMSVGA3DCONTEXT *papContexts;
+ /** Surfaces indexed by ID. Grown as needed. */
+ PVMSVGA3DSURFACE *papSurfaces;
+
+#ifdef RT_OS_WINDOWS
+# ifdef VMSVGA3D_DIRECT3D
+# ifdef VBOX_VMSVGA3D_WITH_WINE_OPENGL
+ IDirect3D9 *pD3D9;
+# else
+ IDirect3D9Ex *pD3D9;
+# endif
+ D3DCAPS9 caps;
+ bool fSupportedSurfaceINTZ;
+ bool fSupportedSurfaceNULL;
+# endif
+ /** Window Thread. */
+ R3PTRTYPE(RTTHREAD) pWindowThread;
+ DWORD idWindowThread;
+ HMODULE hInstance;
+ /** Window request semaphore. */
+ RTSEMEVENT WndRequestSem;
+#elif defined(RT_OS_DARWIN)
+#else
+ /* The X display */
+ Display *display;
+ R3PTRTYPE(RTTHREAD) pWindowThread;
+ bool bTerminate;
+#endif
+
+#ifdef VMSVGA3D_OPENGL
+ float fGLVersion;
+ /* Current active context. */
+ uint32_t idActiveContext;
+
+ struct
+ {
+ PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
+ PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
+ PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
+ PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
+ PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
+ PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
+ PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
+ PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
+ PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
+ PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
+ PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
+ PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
+ PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
+ PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
+ PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
+ PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
+ PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
+ PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
+ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
+ PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
+ PFNGLPOINTPARAMETERFPROC glPointParameterf;
+#if VBOX_VMSVGA3D_GL_HACK_LEVEL < 0x102
+ PFNGLBLENDCOLORPROC glBlendColor;
+ PFNGLBLENDEQUATIONPROC glBlendEquation;
+#endif
+ PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate;
+ PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
+ PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate;
+ PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate;
+ PFNGLBINDBUFFERPROC glBindBuffer;
+ PFNGLDELETEBUFFERSPROC glDeleteBuffers;
+ PFNGLGENBUFFERSPROC glGenBuffers;
+ PFNGLBUFFERDATAPROC glBufferData;
+ PFNGLMAPBUFFERPROC glMapBuffer;
+ PFNGLUNMAPBUFFERPROC glUnmapBuffer;
+ PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
+ PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
+ PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
+ PFNGLFOGCOORDPOINTERPROC glFogCoordPointer;
+ PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex;
+ PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex;
+ PFNGLACTIVETEXTUREPROC glActiveTexture;
+#if VBOX_VMSVGA3D_GL_HACK_LEVEL < 0x103
+ PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
+#endif
+ PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
+ PFNGLPROVOKINGVERTEXPROC glProvokingVertex;
+ bool fEXT_stencil_two_side;
+ } ext;
+
+ struct
+ {
+ GLint maxActiveLights;
+ GLint maxTextureBufferSize;
+ GLint maxTextures;
+ GLint maxClipDistances;
+ GLint maxColorAttachments;
+ GLint maxRectangleTextureSize;
+ GLint maxTextureAnisotropy;
+ GLint maxVertexShaderInstructions;
+ GLint maxFragmentShaderInstructions;
+ GLint maxVertexShaderTemps;
+ GLint maxFragmentShaderTemps;
+ GLfloat flPointSize[2];
+ SVGA3dPixelShaderVersion fragmentShaderVersion;
+ SVGA3dVertexShaderVersion vertexShaderVersion;
+ bool fS3TCSupported;
+ } caps;
+
+ /** The GL_EXTENSIONS value (space padded) for the default OpenGL profile.
+ * Free with RTStrFree. */
+ R3PTRTYPE(char *) pszExtensions;
+
+ /** The GL_EXTENSIONS value (space padded) for the other OpenGL profile.
+ * Free with RTStrFree.
+ *
+ * This is used to detect shader model version since some implementations
+ * (darwin) hides extensions that have made it into core and probably a
+ * bunch of others when using a OpenGL core profile instead of a legacy one */
+ R3PTRTYPE(char *) pszOtherExtensions;
+ /** The version of the other GL profile. */
+ float fOtherGLVersion;
+
+ /** Shader talk back interface. */
+ VBOXVMSVGASHADERIF ShaderIf;
+
+# ifdef VMSVGA3D_OPENGL
+ /** The shared context. */
+ VMSVGA3DCONTEXT SharedCtx;
+# endif
+#endif /* VMSVGA3D_OPENGL */
+} VMSVGA3DSTATE;
+
+#ifdef VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+/**
+ * SSM descriptor table for the VMSVGA3DSTATE structure.
+ *
+ * @remarks This isn't a complete structure markup, only fields with state.
+ */
+static SSMFIELD const g_aVMSVGA3DSTATEFields[] =
+{
+# ifdef VMSVGA3D_OPENGL
+ SSMFIELD_ENTRY( VMSVGA3DSTATE, fGLVersion), /** @todo Why are we saving the GL version?? */
+# endif
+ SSMFIELD_ENTRY( VMSVGA3DSTATE, cContexts),
+ SSMFIELD_ENTRY( VMSVGA3DSTATE, cSurfaces),
+ SSMFIELD_ENTRY_TERM()
+};
+#endif /* VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS */
+
+
+#ifdef VMSVGA3D_DIRECT3D
+D3DFORMAT vmsvga3dSurfaceFormat2D3D(SVGA3dSurfaceFormat format);
+D3DMULTISAMPLE_TYPE vmsvga3dMultipeSampleCount2D3D(uint32_t multisampleCount);
+DECLCALLBACK(int) vmsvga3dSharedSurfaceDestroyTree(PAVLU32NODECORE pNode, void *pvParam);
+int vmsvga3dSurfaceFlush(PVGASTATE pThis, PVMSVGA3DSURFACE pSurface);
+#endif /* VMSVGA3D_DIRECT3D */
+
+
+#ifdef VMSVGA3D_OPENGL
+/** Save and setup everything. */
+# define VMSVGA3D_PARANOID_TEXTURE_PACKING
+
+/**
+ * Saved texture packing parameters (shared by both pack and unpack).
+ */
+typedef struct VMSVGAPACKPARAMS
+{
+ GLint iAlignment;
+ GLint cxRow;
+# ifdef VMSVGA3D_PARANOID_TEXTURE_PACKING
+ GLint cyImage;
+ GLboolean fSwapBytes;
+ GLboolean fLsbFirst;
+ GLint cSkipRows;
+ GLint cSkipPixels;
+ GLint cSkipImages;
+# endif
+} VMSVGAPACKPARAMS;
+/** Pointer to saved texture packing parameters. */
+typedef VMSVGAPACKPARAMS *PVMSVGAPACKPARAMS;
+/** Pointer to const saved texture packing parameters. */
+typedef VMSVGAPACKPARAMS const *PCVMSVGAPACKPARAMS;
+
+void vmsvga3dOglSetPackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PVMSVGAPACKPARAMS pSave);
+void vmsvga3dOglRestorePackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PCVMSVGAPACKPARAMS pSave);
+void vmsvga3dOglSetUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PVMSVGAPACKPARAMS pSave);
+void vmsvga3dOglRestoreUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PCVMSVGAPACKPARAMS pSave);
+
+/** @name VMSVGA3D_DEF_CTX_F_XXX - vmsvga3dContextDefineOgl flags.
+ * @{ */
+/** When clear, the context is created using the default OpenGL profile.
+ * When set, it's created using the alternative profile. The latter is only
+ * allowed if the VBOX_VMSVGA3D_DUAL_OPENGL_PROFILE is set. */
+# define VMSVGA3D_DEF_CTX_F_OTHER_PROFILE RT_BIT_32(0)
+/** Defining the shared context. */
+# define VMSVGA3D_DEF_CTX_F_SHARED_CTX RT_BIT_32(1)
+/** Defining the init time context (EMT). */
+# define VMSVGA3D_DEF_CTX_F_INIT RT_BIT_32(2)
+/** @} */
+int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFlags);
+void vmsvga3dSurfaceFormat2OGL(PVMSVGA3DSURFACE pSurface, SVGA3dSurfaceFormat format);
+
+#endif /* VMSVGA3D_OPENGL */
+
+
+/* DevVGA-SVGA3d-shared.cpp: */
+uint32_t vmsvga3dSaveShaderConst(PVMSVGA3DCONTEXT pContext, uint32_t reg, SVGA3dShaderType type, SVGA3dShaderConstType ctype,
+ uint32_t val1, uint32_t val2, uint32_t val3, uint32_t val4);
+
+
+
+/* Command implementation workers. */
+void vmsvga3dBackSurfaceDestroy(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface);
+int vmsvga3dBackSurfaceStretchBlt(PVGASTATE pThis, PVMSVGA3DSTATE pState,
+ PVMSVGA3DSURFACE pDstSurface, uint32_t uDstMipmap, SVGA3dBox const *pDstBox,
+ PVMSVGA3DSURFACE pSrcSurface, uint32_t uSrcMipmap, SVGA3dBox const *pSrcBox,
+ SVGA3dStretchBltMode enmMode, PVMSVGA3DCONTEXT pContext);
+int vmsvga3dBackSurfaceDMACopyBox(PVGASTATE pThis, PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, uint32_t uHostMimap,
+ SVGAGuestPtr GuestPtr, uint32_t cbSrcPitch, SVGA3dTransferType transfer,
+ SVGA3dCopyBox const *pBox, PVMSVGA3DCONTEXT pContext, int rc, int iBox);
+
+int vmsvga3dBackCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext,
+ PVMSVGA3DSURFACE pSurface);
+
+#endif
+
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-ogl.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-ogl.cpp
index 33e862d..d569d54 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-ogl.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-ogl.cpp
@@ -16,15 +16,15 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
/* Enable to disassemble defined shaders. (Windows host only) */
#if defined(RT_OS_WINDOWS) && defined(DEBUG) && 0 /* Disabled as we don't have the DirectX SDK avaible atm. */
# define DUMP_SHADER_DISASSEMBLY
#endif
#ifdef DEBUG_bird
-# define RTMEM_WRAP_TO_EF_APIS
+//# define RTMEM_WRAP_TO_EF_APIS
#endif
#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
#include <VBox/vmm/pdmdev.h>
@@ -37,99 +37,28 @@
#include <iprt/semaphore.h>
#include <iprt/uuid.h>
#include <iprt/mem.h>
-#include <iprt/avl.h>
-#include <VBox/VMMDev.h>
-#include <VBox/VBoxVideo.h>
-#include <VBox/bioslogo.h>
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
#include "DevVGA.h"
#include "DevVGA-SVGA.h"
#include "DevVGA-SVGA3d.h"
-#include "vmsvga/svga_reg.h"
-#include "vmsvga/svga3d_reg.h"
-#include "vmsvga/svga3d_shaderdefs.h"
+#include "DevVGA-SVGA3d-internal.h"
-#ifdef RT_OS_WINDOWS
-# include <GL/gl.h>
-# include "vmsvga_glext/wglext.h"
-
-#elif defined(RT_OS_DARWIN)
-# include <OpenGL/OpenGL.h>
-# include <OpenGL/gl3.h>
-# include <OpenGL/gl3ext.h>
-# define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
-# include <OpenGL/gl.h>
-# include <OpenGL/glext.h>
-# include "DevVGA-SVGA3d-cocoa.h"
-/* work around conflicting definition of GLhandleARB in VMware's glext.h */
-//#define GL_ARB_shader_objects
-// HACK
-typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
-typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
-typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
-# define GL_RGBA_S3TC 0x83A2
-# define GL_ALPHA8_EXT 0x803c
-# define GL_LUMINANCE8_EXT 0x8040
-# define GL_LUMINANCE16_EXT 0x8042
-# define GL_LUMINANCE4_ALPHA4_EXT 0x8043
-# define GL_LUMINANCE8_ALPHA8_EXT 0x8045
-# define GL_INT_2_10_10_10_REV 0x8D9F
-#else
-# include <X11/Xlib.h>
-# include <X11/Xatom.h>
-# include <GL/gl.h>
-# include <GL/glx.h>
-# include <GL/glext.h>
-# define VBOX_VMSVGA3D_GL_HACK_LEVEL 0x103
-#endif
#ifdef DUMP_SHADER_DISASSEMBLY
# include <d3dx9shader.h>
#endif
-#include "vmsvga_glext/glext.h"
-
-#include "shaderlib/shaderlib.h"
#include <stdlib.h>
#include <math.h>
-#include <float.h>
-
-
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
-/** Experimental: Create a dedicated context for handling surfaces in, thus
- * avoiding orphaned surfaces after context destruction.
- *
- * This cures, for instance, an assertion on fedora 21 that happens in
- * vmsvga3dSurfaceStretchBlt if the login screen and the desktop has different
- * sizes. The context of the login screen seems to have just been destroyed
- * earlier and I believe the driver/X/whoever is attemting to strech the old
- * screen content onto the new sized screen.
- *
- * @remarks This probably comes at a slight preformance expense, as we currently
- * switches context when setting up the surface the first time. Not sure
- * if we really need to, but as this is an experiment, I'm playing it safe.
- */
-#define VMSVGA3D_OGL_WITH_SHARED_CTX
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
-/** Fake surface ID for the shared context. */
-# define VMSVGA3D_SHARED_CTX_ID UINT32_C(0xffffeeee)
-#endif
+#include <float.h> /* FLT_MIN */
-/** @def VBOX_VMSVGA3D_GL_HACK_LEVEL
- * Turns out that on Linux gl.h may often define the first 2-4 OpenGL versions
- * worth of extensions, but missing out on a function pointer of fifteen. This
- * causes headache for us when we use the function pointers below. This hack
- * changes the code to call the known problematic functions directly.
- * The value is ((x)<<16 | (y)) where x and y are taken from the GL_VERSION_x_y.
- */
-#ifndef VBOX_VMSVGA3D_GL_HACK_LEVEL
-# define VBOX_VMSVGA3D_GL_HACK_LEVEL 0
-#endif
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
#ifndef VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE
# define VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE 1.0
#endif
@@ -158,278 +87,11 @@ static void *MyNSGLGetProcAddress(const char *pszSymbol)
#define D3D_TO_OGL_Y_COORD(ptrSurface, y_coordinate) (ptrSurface->pMipmapLevels[0].size.height - (y_coordinate))
#define D3D_TO_OGL_Y_COORD_MIPLEVEL(ptrMipLevel, y_coordinate) (ptrMipLevel->size.height - (y_coordinate))
-#define OPENGL_INVALID_ID 0
-
//#define MANUAL_FLIP_SURFACE_DATA
/* Enable to render the result of DrawPrimitive in a seperate window. */
//#define DEBUG_GFX_WINDOW
-/** @name VMSVGA3D_DEF_CTX_F_XXX - vmsvga3dContextDefineOgl flags.
- * @{ */
-/** When clear, the context is created using the default OpenGL profile.
- * When set, it's created using the alternative profile. The latter is only
- * allowed if the VBOX_VMSVGA3D_DUAL_OPENGL_PROFILE is set. */
-#define VMSVGA3D_DEF_CTX_F_OTHER_PROFILE RT_BIT_32(0)
-/** Defining the shared context. */
-#define VMSVGA3D_DEF_CTX_F_SHARED_CTX RT_BIT_32(1)
-/** Defining the init time context (EMT). */
-#define VMSVGA3D_DEF_CTX_F_INIT RT_BIT_32(2)
-/** @} */
-
-
-#define VMSVGA3D_CLEAR_CURRENT_CONTEXT(pState) \
- do { (pState)->idActiveContext = OPENGL_INVALID_ID; } while (0)
-
-/** @def VMSVGA3D_SET_CURRENT_CONTEXT
- * Makes sure the @a pContext is the active OpenGL context.
- * @parm pState The VMSVGA3d state.
- * @parm pContext The new context.
- */
-#ifdef RT_OS_WINDOWS
-# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
- if ((pState)->idActiveContext != (pContext)->id) \
- { \
- BOOL fMakeCurrentRc = wglMakeCurrent((pContext)->hdc, (pContext)->hglrc); \
- Assert(fMakeCurrentRc == TRUE); \
- LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
- (pState)->idActiveContext = (pContext)->id; \
- } else do { } while (0)
-
-#elif defined(RT_OS_DARWIN)
-# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
- if ((pState)->idActiveContext != (pContext)->id) \
- { \
- vmsvga3dCocoaViewMakeCurrentContext((pContext)->cocoaView, (pContext)->cocoaContext); \
- LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
- (pState)->idActiveContext = (pContext)->id; \
- } else do { } while (0)
-#else
-# define VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext) \
- if ((pState)->idActiveContext != (pContext)->id) \
- { \
- Bool fMakeCurrentRc = glXMakeCurrent((pState)->display, \
- (pContext)->window, \
- (pContext)->glxContext); \
- Assert(fMakeCurrentRc == True); \
- LogFlowFunc(("Changing context: %#x -> %#x\n", (pState)->idActiveContext, (pContext)->id)); \
- (pState)->idActiveContext = (pContext)->id; \
- } else do { } while (0)
-#endif
-
-/** @def VMSVGA3D_CLEAR_GL_ERRORS
- * Clears all pending OpenGL errors.
- *
- * If I understood this correctly, OpenGL maintains a bitmask internally and
- * glGetError gets the next bit (clearing it) from the bitmap and translates it
- * into a GL_XXX constant value which it then returns. A single OpenGL call can
- * set more than one bit, and they stick around across calls, from what I
- * understand.
- *
- * So in order to be able to use glGetError to check whether a function
- * succeeded, we need to call glGetError until all error bits have been cleared.
- * This macro does that (in all types of builds).
- *
- * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS
- */
-#define VMSVGA3D_CLEAR_GL_ERRORS() \
- do { \
- if (RT_UNLIKELY(glGetError() != GL_NO_ERROR)) /* predict no errors pending */ \
- { \
- uint32_t iErrorClearingLoopsLeft = 64; \
- while (glGetError() != GL_NO_ERROR && iErrorClearingLoopsLeft > 0) \
- iErrorClearingLoopsLeft--; \
- } \
- } while (0)
-
-/** @def VMSVGA3D_GET_LAST_GL_ERROR
- * Gets the last OpenGL error, stores it in a_pContext->lastError and returns
- * it.
- *
- * @returns Same as glGetError.
- * @param a_pContext The context to store the error in.
- *
- * @sa VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_GET_GL_ERROR(a_pContext) ((a_pContext)->lastError = glGetError())
-
-/** @def VMSVGA3D_GL_SUCCESS
- * Checks whether VMSVGA3D_GET_LAST_GL_ERROR() return GL_NO_ERROR.
- *
- * Will call glGetError() and store the result in a_pContext->lastError.
- * Will predict GL_NO_ERROR outcome.
- *
- * @returns True on success, false on error.
- * @parm a_pContext The context to store the error in.
- *
- * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_GL_IS_SUCCESS(a_pContext) RT_LIKELY((((a_pContext)->lastError = glGetError()) == GL_NO_ERROR))
-
-/** @def VMSVGA3D_GL_COMPLAIN
- * Complains about one or more OpenGL errors (first in a_pContext->lastError).
- *
- * Strict builds will trigger an assertion, while other builds will put the
- * first few occurences in the release log.
- *
- * All GL errors will be cleared after invocation. Assumes lastError
- * is an error, will not check for GL_NO_ERROR.
- *
- * @param a_pState The 3D state structure.
- * @param a_pContext The context that holds the first error.
- * @param a_LogRelDetails Argument list for LogRel or similar that describes
- * the operation in greater detail.
- *
- * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS
- */
-#ifdef VBOX_STRICT
-# define VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
- do { \
- AssertMsg((a_pState)->idActiveContext == (a_pContext)->id, \
- ("idActiveContext=%#x id=%x\n", (a_pState)->idActiveContext, (a_pContext)->id)); \
- RTAssertMsg2Weak a_LogRelDetails; \
- GLenum iNextError; \
- while ((iNextError = glGetError()) != GL_NO_ERROR) \
- RTAssertMsg2Weak("next error: %#x\n", iNextError); \
- AssertMsgFailed(("first error: %#x (idActiveContext=%#x)\n", (a_pContext)->lastError, (a_pContext)->id)); \
- } while (0)
-#else
-# define VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
- do { \
- LogRelMax(32, ("VMSVGA3d: OpenGL error %#x (idActiveContext=%#x) on line %u ", (a_pContext)->lastError, (a_pContext)->id)); \
- GLenum iNextError; \
- while ((iNextError = glGetError()) != GL_NO_ERROR) \
- LogRelMax(32, (" - also error %#x ", iNextError)); \
- LogRelMax(32, a_LogRelDetails); \
- } while (0)
-#endif
-
-/** @def VMSVGA3D_GL_GET_AND_COMPLAIN
- * Combination of VMSVGA3D_GET_GL_ERROR and VMSVGA3D_GL_COMPLAIN, assuming that
- * there is a pending error.
- *
- * @param a_pState The 3D state structure.
- * @param a_pContext The context that holds the first error.
- * @param a_LogRelDetails Argument list for LogRel or similar that describes
- * the operation in greater detail.
- *
- * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_GL_GET_AND_COMPLAIN(a_pState, a_pContext, a_LogRelDetails) \
- do { \
- VMSVGA3D_GET_GL_ERROR(a_pContext); \
- VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails); \
- } while (0)
-
-/** @def VMSVGA3D_GL_ASSERT_SUCCESS
- * Asserts that VMSVGA3D_GL_IS_SUCCESS is true, complains if not.
- *
- * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
- * logging in non-strict builds.
- *
- * @param a_pState The 3D state structure.
- * @param a_pContext The context that holds the first error.
- * @param a_LogRelDetails Argument list for LogRel or similar that describes
- * the operation in greater detail.
- *
- * @sa VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_GL_ASSERT_SUCCESS(a_pState, a_pContext, a_LogRelDetails) \
- if (VMSVGA3D_GL_IS_SUCCESS(a_pContext)) \
- { /* likely */ } \
- else do { \
- VMSVGA3D_GL_COMPLAIN(a_pState, a_pContext, a_LogRelDetails); \
- } while (0)
-
-/** @def VMSVGA3D_ASSERT_GL_CALL_EX
- * Executes the specified OpenGL API call and asserts that it succeeded, variant
- * with extra logging flexibility.
- *
- * ASSUMES no GL errors pending prior to invocation - caller should use
- * VMSVGA3D_CLEAR_GL_ERRORS if uncertain.
- *
- * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
- * logging in non-strict builds.
- *
- * @param a_GlCall Expression making an OpenGL call.
- * @param a_pState The 3D state structure.
- * @param a_pContext The context that holds the first error.
- * @param a_LogRelDetails Argument list for LogRel or similar that describes
- * the operation in greater detail.
- *
- * @sa VMSVGA3D_ASSERT_GL_CALL, VMSVGA3D_GL_ASSERT_SUCCESS,
- * VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_ASSERT_GL_CALL_EX(a_GlCall, a_pState, a_pContext, a_LogRelDetails) \
- do { \
- (a_GlCall); \
- VMSVGA3D_GL_ASSERT_SUCCESS(a_pState, a_pContext, a_LogRelDetails); \
- } while (0)
-
-/** @def VMSVGA3D_ASSERT_GL_CALL
- * Executes the specified OpenGL API call and asserts that it succeeded.
- *
- * ASSUMES no GL errors pending prior to invocation - caller should use
- * VMSVGA3D_CLEAR_GL_ERRORS if uncertain.
- *
- * Uses VMSVGA3D_GL_COMPLAIN for complaining, so check it out wrt to release
- * logging in non-strict builds.
- *
- * @param a_GlCall Expression making an OpenGL call.
- * @param a_pState The 3D state structure.
- * @param a_pContext The context that holds the first error.
- *
- * @sa VMSVGA3D_ASSERT_GL_CALL_EX, VMSVGA3D_GL_ASSERT_SUCCESS,
- * VMSVGA3D_GET_GL_ERROR, VMSVGA3D_GL_IS_SUCCESS, VMSVGA3D_GL_COMPLAIN
- */
-#define VMSVGA3D_ASSERT_GL_CALL(a_GlCall, a_pState, a_pContext) \
- VMSVGA3D_ASSERT_GL_CALL_EX(a_GlCall, a_pState, a_pContext, ("%s\n", #a_GlCall))
-
-
-/** @def VMSVGA3D_CHECK_LAST_ERROR
- * Checks that the last OpenGL error code indicates success.
- *
- * Will assert and return VERR_INTERNAL_ERROR in strict builds, in other
- * builds it will do nothing and is a NOOP.
- *
- * @parm pState The VMSVGA3d state.
- * @parm pContext The context.
- *
- * @todo Replace with proper error handling, it's crazy to return
- * VERR_INTERNAL_ERROR in strict builds and just barge on ahead in
- * release builds.
- */
-#ifdef VBOX_STRICT
-# define VMSVGA3D_CHECK_LAST_ERROR(pState, pContext) do { \
- Assert((pState)->idActiveContext == (pContext)->id); \
- (pContext)->lastError = glGetError(); \
- AssertMsgReturn((pContext)->lastError == GL_NO_ERROR, \
- ("%s (%d): last error 0x%x\n", __FUNCTION__, __LINE__, (pContext)->lastError), \
- VERR_INTERNAL_ERROR); \
- } while (0)
-#else
-# define VMSVGA3D_CHECK_LAST_ERROR(pState, pContext) do { } while (0)
-#endif
-
-/** @def VMSVGA3D_CHECK_LAST_ERROR_WARN
- * Checks that the last OpenGL error code indicates success.
- *
- * Will assert in strict builds, otherwise it's a NOOP.
- *
- * @parm pState The VMSVGA3d state.
- * @parm pContext The new context.
- */
-#ifdef VBOX_STRICT
-# define VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext) do { \
- Assert((pState)->idActiveContext == (pContext)->id); \
- (pContext)->lastError = glGetError(); \
- AssertMsg((pContext)->lastError == GL_NO_ERROR, ("%s (%d): last error 0x%x\n", __FUNCTION__, __LINE__, (pContext)->lastError)); \
- } while (0)
-#else
-# define VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext) do { } while (0)
-#endif
-
-
/**
* Macro for doing something and then checking for errors during initialization.
* Uses AssertLogRelMsg.
@@ -473,466 +135,11 @@ static void *MyNSGLGetProcAddress(const char *pszSymbol)
#endif
-/*******************************************************************************
-* Structures, Typedefs and Globals. *
-*******************************************************************************/
-typedef struct
-{
- SVGA3dSize size;
- uint32_t cbSurface;
- uint32_t cbSurfacePitch;
- void *pSurfaceData;
- bool fDirty;
-} VMSVGA3DMIPMAPLEVEL, *PVMSVGA3DMIPMAPLEVEL;
-
-/**
- * SSM descriptor table for the VMSVGA3DMIPMAPLEVEL structure.
- */
-static SSMFIELD const g_aVMSVGA3DMIPMAPLEVELFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, size),
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurface),
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurfacePitch),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DMIPMAPLEVEL, pSurfaceData),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DMIPMAPLEVEL, fDirty),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- uint32_t id;
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- uint32_t idWeakContextAssociation;
-#else
- uint32_t idAssociatedContext;
-#endif
- uint32_t flags;
- SVGA3dSurfaceFormat format;
- GLint internalFormatGL;
- GLint formatGL;
- GLint typeGL;
- union
- {
- GLuint texture;
- GLuint buffer;
- GLuint renderbuffer;
- } oglId;
- SVGA3dSurfaceFace faces[SVGA3D_MAX_SURFACE_FACES];
- uint32_t cFaces;
- PVMSVGA3DMIPMAPLEVEL pMipmapLevels;
- uint32_t multiSampleCount;
- SVGA3dTextureFilter autogenFilter;
- uint32_t cbBlock; /* block/pixel size in bytes */
- /* Dirty state; surface was manually updated. */
- bool fDirty;
-} VMSVGA3DSURFACE, *PVMSVGA3DSURFACE;
-
-/**
- * SSM descriptor table for the VMSVGA3DSURFACE structure.
- */
-static SSMFIELD const g_aVMSVGA3DSURFACEFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, id),
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, idWeakContextAssociation),
-#else
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, idAssociatedContext),
-#endif
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, flags),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, format),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, internalFormatGL),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, formatGL),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, typeGL),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, id),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, faces),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, cFaces),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, pMipmapLevels),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, multiSampleCount),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, autogenFilter),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, cbBlock),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fDirty),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- uint32_t id;
- uint32_t cid;
- SVGA3dShaderType type;
- uint32_t cbData;
- void *pShaderProgram;
- union
- {
- void *pVertexShader;
- void *pPixelShader;
- } u;
-} VMSVGA3DSHADER, *PVMSVGA3DSHADER;
-
-/**
- * SSM descriptor table for the VMSVGA3DSHADER structure.
- */
-static SSMFIELD const g_aVMSVGA3DSHADERFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DSHADER, id),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, cid),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, type),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, cbData),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, pShaderProgram),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, u.pVertexShader),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- bool fValid;
- float matrix[16];
-} VMSVGATRANSFORMSTATE, *PVMSVGATRANSFORMSTATE;
-
-typedef struct
-{
- bool fValid;
- SVGA3dMaterial material;
-} VMSVGAMATERIALSTATE, *PVMSVGAMATERIALSTATE;
-
-typedef struct
-{
- bool fValid;
- float plane[4];
-} VMSVGACLIPPLANESTATE, *PVMSVGACLIPPLANESTATE;
-
-typedef struct
-{
- bool fEnabled;
- bool fValidData;
- SVGA3dLightData data;
-} VMSVGALIGHTSTATE, *PVMSVGALIGHTSTATE;
-
-typedef struct
-{
- bool fValid;
- SVGA3dShaderConstType ctype;
- uint32_t value[4];
-} VMSVGASHADERCONST, *PVMSVGASHADERCONST;
-
-/**
- * SSM descriptor table for the VMSVGASHADERCONST structure.
- */
-static SSMFIELD const g_aVMSVGASHADERCONSTFields[] =
-{
- SSMFIELD_ENTRY( VMSVGASHADERCONST, fValid),
- SSMFIELD_ENTRY( VMSVGASHADERCONST, ctype),
- SSMFIELD_ENTRY( VMSVGASHADERCONST, value),
- SSMFIELD_ENTRY_TERM()
-};
-
-#define VMSVGA3D_UPDATE_SCISSORRECT RT_BIT(0)
-#define VMSVGA3D_UPDATE_ZRANGE RT_BIT(1)
-#define VMSVGA3D_UPDATE_VIEWPORT RT_BIT(2)
-#define VMSVGA3D_UPDATE_VERTEXSHADER RT_BIT(3)
-#define VMSVGA3D_UPDATE_PIXELSHADER RT_BIT(4)
-#define VMSVGA3D_UPDATE_TRANSFORM RT_BIT(5)
-#define VMSVGA3D_UPDATE_MATERIAL RT_BIT(6)
-
-typedef struct VMSVGA3DCONTEXT
-{
- uint32_t id;
-#ifdef RT_OS_WINDOWS
- /* Device context of the context window. */
- HDC hdc;
- /* OpenGL rendering context handle. */
- HGLRC hglrc;
- /* Device context window handle. */
- HWND hwnd;
-#elif defined(RT_OS_DARWIN)
- /* OpenGL rendering context */
- NativeNSOpenGLContextRef cocoaContext;
- NativeNSViewRef cocoaView;
- bool fOtherProfile;
-#else
- /** XGL rendering context handle */
- GLXContext glxContext;
- /** Device context window handle */
- Window window;
- /** flag whether the window is mapped (=visible) */
- bool fMapped;
-#endif
- /* Framebuffer object associated with this context. */
- GLuint idFramebuffer;
- /* Read and draw framebuffer objects for various operations. */
- GLuint idReadFramebuffer;
- GLuint idDrawFramebuffer;
- /* Last GL error recorded. */
- GLenum lastError;
-
- /* Current active render target (if any) */
- uint32_t sidRenderTarget;
- /* Current selected texture surfaces (if any) */
- uint32_t aSidActiveTexture[SVGA3D_MAX_TEXTURE_STAGE];
- /* Per context pixel and vertex shaders. */
- uint32_t cPixelShaders;
- PVMSVGA3DSHADER paPixelShader;
- uint32_t cVertexShaders;
- PVMSVGA3DSHADER paVertexShader;
- void *pShaderContext;
- /* Keep track of the internal state to be able to recreate the context properly (save/restore, window resize). */
- struct
- {
- uint32_t u32UpdateFlags;
-
- SVGA3dRenderState aRenderState[SVGA3D_RS_MAX];
- SVGA3dTextureState aTextureState[SVGA3D_MAX_TEXTURE_STAGE][SVGA3D_TS_MAX];
- VMSVGATRANSFORMSTATE aTransformState[SVGA3D_TRANSFORM_MAX];
- VMSVGAMATERIALSTATE aMaterial[SVGA3D_FACE_MAX];
- VMSVGACLIPPLANESTATE aClipPlane[SVGA3D_CLIPPLANE_MAX];
- VMSVGALIGHTSTATE aLightData[SVGA3D_MAX_LIGHTS];
-
- uint32_t aRenderTargets[SVGA3D_RT_MAX];
- SVGA3dRect RectScissor;
- SVGA3dRect RectViewPort;
- SVGA3dZRange zRange;
- uint32_t shidPixel;
- uint32_t shidVertex;
-
- uint32_t cPixelShaderConst;
- PVMSVGASHADERCONST paPixelShaderConst;
- uint32_t cVertexShaderConst;
- PVMSVGASHADERCONST paVertexShaderConst;
- } state;
-} VMSVGA3DCONTEXT, *PVMSVGA3DCONTEXT;
-
-/**
- * SSM descriptor table for the VMSVGA3DCONTEXT structure.
- */
-static SSMFIELD const g_aVMSVGA3DCONTEXTFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, id),
-#ifdef RT_OS_WINDOWS
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hdc),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hglrc),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, hwnd),
-#endif
-
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idFramebuffer),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idReadFramebuffer),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, idDrawFramebuffer),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, lastError),
-
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, sidRenderTarget),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, aSidActiveTexture),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cPixelShaders),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paPixelShader),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cVertexShaders),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paVertexShader),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, pShaderContext),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.u32UpdateFlags),
-
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTextureState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTransformState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aMaterial),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aClipPlane),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aLightData),
-
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderTargets),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectScissor),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectViewPort),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.zRange),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidPixel),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidVertex),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cPixelShaderConst),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paPixelShaderConst),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cVertexShaderConst),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paVertexShaderConst),
- SSMFIELD_ENTRY_TERM()
-};
-
-/**
- * VMSVGA3d state data.
- *
- * Allocated on the heap and pointed to by VMSVGAState::p3dState.
- */
-typedef struct VMSVGA3DSTATE
-{
-#ifdef RT_OS_WINDOWS
- /** Window Thread. */
- R3PTRTYPE(RTTHREAD) pWindowThread;
- DWORD idWindowThread;
- HMODULE hInstance;
- /** Window request semaphore. */
- RTSEMEVENT WndRequestSem;
-#elif defined(RT_OS_LINUX)
- /* The X display */
- Display *display;
- R3PTRTYPE(RTTHREAD) pWindowThread;
- bool bTerminate;
-#endif
-
- float fGLVersion;
- /* Current active context. */
- uint32_t idActiveContext;
-
- struct
- {
- PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
- PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
- PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
- PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
- PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
- PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
- PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
- PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
- PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
- PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
- PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
- PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
- PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
- PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
- PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
- PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
- PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
- PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
- PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
- PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
- PFNGLPOINTPARAMETERFPROC glPointParameterf;
-#if VBOX_VMSVGA3D_GL_HACK_LEVEL < 0x102
- PFNGLBLENDCOLORPROC glBlendColor;
- PFNGLBLENDEQUATIONPROC glBlendEquation;
-#endif
- PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate;
- PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
- PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate;
- PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate;
- PFNGLBINDBUFFERPROC glBindBuffer;
- PFNGLDELETEBUFFERSPROC glDeleteBuffers;
- PFNGLGENBUFFERSPROC glGenBuffers;
- PFNGLBUFFERDATAPROC glBufferData;
- PFNGLMAPBUFFERPROC glMapBuffer;
- PFNGLUNMAPBUFFERPROC glUnmapBuffer;
- PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
- PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
- PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
- PFNGLFOGCOORDPOINTERPROC glFogCoordPointer;
- PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex;
- PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex;
- PFNGLACTIVETEXTUREPROC glActiveTexture;
-#if VBOX_VMSVGA3D_GL_HACK_LEVEL < 0x103
- PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
-#endif
- PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
- PFNGLPROVOKINGVERTEXPROC glProvokingVertex;
- bool fEXT_stencil_two_side;
- } ext;
-
- struct
- {
- GLint maxActiveLights;
- GLint maxTextureBufferSize;
- GLint maxTextures;
- GLint maxClipDistances;
- GLint maxColorAttachments;
- GLint maxRectangleTextureSize;
- GLint maxTextureAnisotropy;
- GLint maxVertexShaderInstructions;
- GLint maxFragmentShaderInstructions;
- GLint maxVertexShaderTemps;
- GLint maxFragmentShaderTemps;
- GLfloat flPointSize[2];
- SVGA3dPixelShaderVersion fragmentShaderVersion;
- SVGA3dVertexShaderVersion vertexShaderVersion;
- bool fS3TCSupported;
- } caps;
-
- uint32_t cContexts;
- PVMSVGA3DCONTEXT *papContexts;
- uint32_t cSurfaces;
- PVMSVGA3DSURFACE *papSurfaces;
-#ifdef DEBUG_GFX_WINDOW_TEST_CONTEXT
- uint32_t idTestContext;
-#endif
- /** The GL_EXTENSIONS value (space padded) for the default OpenGL profile.
- * Free with RTStrFree. */
- R3PTRTYPE(char *) pszExtensions;
-
- /** The GL_EXTENSIONS value (space padded) for the other OpenGL profile.
- * Free with RTStrFree.
- *
- * This is used to detect shader model version since some implementations
- * (darwin) hides extensions that have made it into core and probably a
- * bunch of others when using a OpenGL core profile instead of a legacy one */
- R3PTRTYPE(char *) pszOtherExtensions;
- /** The version of the other GL profile. */
- float fOtherGLVersion;
-
- /** Shader talk back interface. */
- VBOXVMSVGASHADERIF ShaderIf;
-
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- /** The shared context. */
- VMSVGA3DCONTEXT SharedCtx;
-#endif
-} VMSVGA3DSTATE;
-/** Pointer to the VMSVGA3d state. */
-typedef VMSVGA3DSTATE *PVMSVGA3DSTATE;
-
-/**
- * SSM descriptor table for the VMSVGA3DSTATE structure.
- */
-static SSMFIELD const g_aVMSVGA3DSTATEFields[] =
-{
-#ifdef RT_OS_WINDOWS
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, pWindowThread),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, idWindowThread),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, hInstance),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, WndRequestSem),
-#elif defined(RT_OS_LINUX)
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, display),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, pWindowThread),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, bTerminate),
-#endif
- SSMFIELD_ENTRY( VMSVGA3DSTATE, fGLVersion),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, idActiveContext),
-
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, ext),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, caps),
-
- SSMFIELD_ENTRY( VMSVGA3DSTATE, cContexts),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, papContexts),
- SSMFIELD_ENTRY( VMSVGA3DSTATE, cSurfaces),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, papSurfaces),
- SSMFIELD_ENTRY_TERM()
-};
-
-
-/** Save and setup everything. */
-#define VMSVGA3D_PARANOID_TEXTURE_PACKING
-
-/**
- * Saved texture packing parameters (shared by both pack and unpack).
- */
-typedef struct VMSVGAPACKPARAMS
-{
- GLint iAlignment;
- GLint cxRow;
-#ifdef VMSVGA3D_PARANOID_TEXTURE_PACKING
- GLint cyImage;
- GLboolean fSwapBytes;
- GLboolean fLsbFirst;
- GLint cSkipRows;
- GLint cSkipPixels;
- GLint cSkipImages;
-#endif
-} VMSVGAPACKPARAMS;
-/** Pointer to saved texture packing parameters. */
-typedef VMSVGAPACKPARAMS *PVMSVGAPACKPARAMS;
-/** Pointer to const saved texture packing parameters. */
-typedef VMSVGAPACKPARAMS const *PCVMSVGAPACKPARAMS;
-
-
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
/* Define the default light parameters as specified by MSDN. */
-/* @todo move out; fetched from Wine */
+/** @todo move out; fetched from Wine */
const SVGA3dLightData vmsvga3d_default_light =
{
SVGA3D_LIGHTTYPE_DIRECTIONAL, /* type */
@@ -950,22 +157,14 @@ const SVGA3dLightData vmsvga3d_default_light =
};
-/*******************************************************************************
-* Internal Functions *
-*******************************************************************************/
-static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext, PVMSVGA3DSURFACE pSurface);
-static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFlags);
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int vmsvga3dContextDestroyOgl(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t cid);
static void vmsvgaColor2GLFloatArray(uint32_t color, GLfloat *pRed, GLfloat *pGreen, GLfloat *pBlue, GLfloat *pAlpha);
-static void vmsvga3dSetPackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PVMSVGAPACKPARAMS pSave);
-static void vmsvga3dRestorePackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PCVMSVGAPACKPARAMS pSave);
/* Generated by VBoxDef2LazyLoad from the VBoxSVGA3D.def and VBoxSVGA3DObjC.def files. */
extern "C" int ExplicitlyLoadVBoxSVGA3D(bool fResolveAllImports, PRTERRINFO pErrInfo);
-#ifdef RT_OS_DARWIN
-extern "C" int ExplicitlyLoadVBoxSVGA3DObjC(bool fResolveAllImports, PRTERRINFO pErrInfo);
-#endif
/**
@@ -1394,12 +593,12 @@ int vmsvga3dInit(PVGASTATE pThis)
/*
* Allocate the state.
*/
- pThis->svga.p3dState = RTMemAllocZ(sizeof(VMSVGA3DSTATE));
+ pThis->svga.p3dState = (PVMSVGA3DSTATE)RTMemAllocZ(sizeof(VMSVGA3DSTATE));
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
#ifdef RT_OS_WINDOWS
/* Create event semaphore and async IO thread. */
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
rc = RTSemEventCreate(&pState->WndRequestSem);
if (RT_SUCCESS(rc))
{
@@ -1425,7 +624,7 @@ int vmsvga3dInit(PVGASTATE pThis)
/* We must delay window creation until the PowerOn phase. Init is too early and will cause failures. */
int vmsvga3dPowerOn(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
PVMSVGA3DCONTEXT pContext;
#ifdef VBOX_VMSVGA3D_DUAL_OPENGL_PROFILE
@@ -1645,7 +844,7 @@ int vmsvga3dPowerOn(PVGASTATE pThis)
* ATI does not support higher than SM 2.0 functionality in assembly shaders.
*
*/
- /** @todo: distinguish between vertex and pixel shaders??? */
+ /** @todo distinguish between vertex and pixel shaders??? */
if ( vmsvga3dCheckGLExtension(pState, 0.0f, " GL_NV_gpu_program4 ")
|| strstr(pState->pszOtherExtensions, " GL_NV_gpu_program4 "))
{
@@ -1817,7 +1016,7 @@ int vmsvga3dPowerOn(PVGASTATE pThis)
int vmsvga3dReset(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
/* Destroy all leftover surfaces. */
@@ -1833,12 +1032,16 @@ int vmsvga3dReset(PVGASTATE pThis)
if (pState->papContexts[i]->id != SVGA3D_INVALID_ID)
vmsvga3dContextDestroy(pThis, pState->papContexts[i]->id);
}
+
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ vmsvga3dContextDestroyOgl(pThis, &pState->SharedCtx, VMSVGA3D_SHARED_CTX_ID);
+
return VINF_SUCCESS;
}
int vmsvga3dTerminate(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_WRONG_ORDER);
int rc;
@@ -1876,9 +1079,25 @@ int vmsvga3dTerminate(PVGASTATE pThis)
return VINF_SUCCESS;
}
-/* Shared functions that depend on private structure definitions. */
-#define VMSVGA3D_OPENGL
-#include "DevVGA-SVGA3d-shared.h"
+
+void vmsvga3dUpdateHostScreenViewport(PVGASTATE pThis, uint32_t idScreen, VMSVGAVIEWPORT const *pOldViewport)
+{
+ /** @todo Move the visible framebuffer content here, don't wait for the guest to
+ * redraw it. */
+
+#ifdef RT_OS_DARWIN
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ if ( pState
+ && idScreen == 0
+ && pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ {
+ vmsvga3dCocoaViewUpdateViewport(pState->SharedCtx.cocoaView);
+ }
+#else
+ NOREF(pThis); NOREF(idScreen);
+#endif
+}
+
/**
* Worker for vmsvga3dQueryCaps that figures out supported operations for a
@@ -1896,7 +1115,7 @@ static uint32_t vmsvga3dGetSurfaceFormatSupport(PVMSVGA3DSTATE pState3D, uint32_
{
uint32_t result = 0;
- /* @todo missing:
+ /** @todo missing:
*
* SVGA3DFORMAT_OP_PIXELSIZE
*/
@@ -1922,7 +1141,7 @@ static uint32_t vmsvga3dGetSurfaceFormatSupport(PVMSVGA3DSTATE pState3D, uint32_
break;
}
- /* @todo check hardware caps! */
+ /** @todo check hardware caps! */
switch (idx3dCaps)
{
case SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8:
@@ -2000,7 +1219,7 @@ static uint32_t vmsvga3dGetDepthFormatSupport(PVMSVGA3DSTATE pState3D, uint32_t
{
uint32_t result = 0;
- /* @todo test this somehow */
+ /** @todo test this somehow */
result = SVGA3DFORMAT_OP_ZSTENCIL | SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH;
Log(("CAPS: %s =\n%s\n", vmsvga3dGetCapString(idx3dCaps), vmsvga3dGet3dFormatString(result)));
@@ -2010,7 +1229,7 @@ static uint32_t vmsvga3dGetDepthFormatSupport(PVMSVGA3DSTATE pState3D, uint32_t
int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc = VINF_SUCCESS;
@@ -2095,7 +1314,7 @@ int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
break;
case SVGA3D_DEVCAP_MAX_SHADER_TEXTURES:
- /* @todo ?? */
+ /** @todo ?? */
rc = VERR_INVALID_PARAMETER;
break;
@@ -2169,7 +1388,7 @@ int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
case SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES:
break;
- case SVGA3D_DEVCAP_MAX_RENDER_TARGETS: /* @todo same thing? */
+ case SVGA3D_DEVCAP_MAX_RENDER_TARGETS: /** @todo same thing? */
case SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS:
*pu32Val = pState->caps.maxColorAttachments;
break;
@@ -2282,7 +1501,7 @@ int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
* @remarks Clues to be had in format_texture_info table (wined3d/utils.c) with
* help from wined3dformat_from_d3dformat().
*/
-static void vmsvga3dSurfaceFormat2OGL(PVMSVGA3DSURFACE pSurface, SVGA3dSurfaceFormat format)
+void vmsvga3dSurfaceFormat2OGL(PVMSVGA3DSURFACE pSurface, SVGA3dSurfaceFormat format)
{
switch (format)
{
@@ -2330,7 +1549,7 @@ static void vmsvga3dSurfaceFormat2OGL(PVMSVGA3DSURFACE pSurface, SVGA3dSurfaceFo
pSurface->internalFormatGL = GL_DEPTH_COMPONENT16; /** @todo Wine suggests GL_DEPTH_COMPONENT24. */
pSurface->formatGL = GL_DEPTH_COMPONENT;
pSurface->typeGL = GL_UNSIGNED_SHORT;
- AssertMsgFailed(("Test me - SVGA3D_Z_D16\n"));
+ //AssertMsgFailed(("Test me - SVGA3D_Z_D16\n"));
break;
case SVGA3D_Z_D24S8: /* D3DFMT_D24S8 - WINED3DFMT_D24_UNORM_S8_UINT */
pSurface->internalFormatGL = GL_DEPTH24_STENCIL8;
@@ -2601,336 +1820,74 @@ D3DMULTISAMPLE_TYPE vmsvga3dMultipeSampleCount2D3D(uint32_t multisampleCount)
if (multisampleCount > 16)
return D3DMULTISAMPLE_NONE;
- /* @todo exact same mapping as d3d? */
+ /** @todo exact same mapping as d3d? */
return (D3DMULTISAMPLE_TYPE)multisampleCount;
}
#endif
-int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
- SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
- SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *pMipLevelSize)
+/**
+ * Destroy backend specific surface bits (part of SVGA_3D_CMD_SURFACE_DESTROY).
+ *
+ * @param pState The VMSVGA3d state.
+ * @param pSurface The surface being destroyed.
+ */
+void vmsvga3dBackSurfaceDestroy(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface)
{
- PVMSVGA3DSURFACE pSurface;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- AssertReturn(pState, VERR_NO_MEMORY);
-
- Log(("vmsvga3dSurfaceDefine: sid=%x surfaceFlags=%x format=%s (%x) multiSampleCount=%d autogenFilter=%d, cMipLevels=%d size=(%d,%d,%d)\n",
- sid, surfaceFlags, vmsvgaSurfaceType2String(format), format, multisampleCount, autogenFilter, cMipLevels, pMipLevelSize->width, pMipLevelSize->height, pMipLevelSize->depth));
-
- AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(cMipLevels >= 1, VERR_INVALID_PARAMETER);
- /* Assuming all faces have the same nr of mipmaps. */
- AssertReturn(!(surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels * 6, VERR_INVALID_PARAMETER);
- AssertReturn((surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels, VERR_INVALID_PARAMETER);
-
- if (sid >= pState->cSurfaces)
- {
- /* Grow the array. */
- uint32_t cNew = RT_ALIGN(sid + 15, 16);
- void *pvNew = RTMemRealloc(pState->papSurfaces, sizeof(pState->papSurfaces[0]) * cNew);
- AssertReturn(pvNew, VERR_NO_MEMORY);
- pState->papSurfaces = (PVMSVGA3DSURFACE *)pvNew;
- while (pState->cSurfaces < cNew)
- {
- pSurface = (PVMSVGA3DSURFACE)RTMemAllocZ(sizeof(*pSurface));
- AssertReturn(pSurface, VERR_NO_MEMORY);
- pSurface->id = SVGA3D_INVALID_ID;
- pState->papSurfaces[pState->cSurfaces++] = pSurface;
- }
- }
- pSurface = pState->papSurfaces[sid];
-
- /* If one already exists with this id, then destroy it now. */
- if (pSurface->id != SVGA3D_INVALID_ID)
- vmsvga3dSurfaceDestroy(pThis, sid);
-
- memset(pSurface, 0, sizeof(*pSurface));
- pSurface->id = sid;
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- pSurface->idWeakContextAssociation = SVGA3D_INVALID_ID;
-#else
- pSurface->idAssociatedContext = SVGA3D_INVALID_ID;
-#endif
- vmsvga3dSurfaceFormat2OGL(pSurface, format);
-
- pSurface->oglId.buffer = OPENGL_INVALID_ID;
-
- /* The surface type is sort of undefined now, even though the hints and format can help to clear that up.
- * In some case we'll have to wait until the surface is used to create the D3D object.
- */
- switch (format)
- {
- case SVGA3D_Z_D32:
- case SVGA3D_Z_D16:
- case SVGA3D_Z_D24S8:
- case SVGA3D_Z_D15S1:
- case SVGA3D_Z_D24X8:
- case SVGA3D_Z_DF16:
- case SVGA3D_Z_DF24:
- case SVGA3D_Z_D24S8_INT:
- surfaceFlags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
- break;
-
- /* Texture compression formats */
- case SVGA3D_DXT1:
- case SVGA3D_DXT2:
- case SVGA3D_DXT3:
- case SVGA3D_DXT4:
- case SVGA3D_DXT5:
- /* Bump-map formats */
- case SVGA3D_BUMPU8V8:
- case SVGA3D_BUMPL6V5U5:
- case SVGA3D_BUMPX8L8V8U8:
- case SVGA3D_BUMPL8V8U8:
- case SVGA3D_V8U8:
- case SVGA3D_Q8W8V8U8:
- case SVGA3D_CxV8U8:
- case SVGA3D_X8L8V8U8:
- case SVGA3D_A2W10V10U10:
- case SVGA3D_V16U16:
- /* Typical render target formats; we should allow render target buffers to be used as textures. */
- case SVGA3D_X8R8G8B8:
- case SVGA3D_A8R8G8B8:
- case SVGA3D_R5G6B5:
- case SVGA3D_X1R5G5B5:
- case SVGA3D_A1R5G5B5:
- case SVGA3D_A4R4G4B4:
- surfaceFlags |= SVGA3D_SURFACE_HINT_TEXTURE;
- break;
-
- case SVGA3D_LUMINANCE8:
- case SVGA3D_LUMINANCE4_ALPHA4:
- case SVGA3D_LUMINANCE16:
- case SVGA3D_LUMINANCE8_ALPHA8:
- case SVGA3D_ARGB_S10E5: /* 16-bit floating-point ARGB */
- case SVGA3D_ARGB_S23E8: /* 32-bit floating-point ARGB */
- case SVGA3D_A2R10G10B10:
- case SVGA3D_ALPHA8:
- case SVGA3D_R_S10E5:
- case SVGA3D_R_S23E8:
- case SVGA3D_RG_S10E5:
- case SVGA3D_RG_S23E8:
- case SVGA3D_G16R16:
- case SVGA3D_A16B16G16R16:
- case SVGA3D_UYVY:
- case SVGA3D_YUY2:
- case SVGA3D_NV12:
- case SVGA3D_AYUV:
- case SVGA3D_BC4_UNORM:
- case SVGA3D_BC5_UNORM:
- break;
-
- /*
- * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
- * the most efficient format to use when creating new surfaces
- * expressly for index or vertex data.
- */
- case SVGA3D_BUFFER:
- break;
-
- default:
- break;
- }
-
- pSurface->flags = surfaceFlags;
- pSurface->format = format;
- memcpy(pSurface->faces, face, sizeof(pSurface->faces));
- pSurface->cFaces = 1; /* check for cube maps later */
- pSurface->multiSampleCount = multisampleCount;
- pSurface->autogenFilter = autogenFilter;
- Assert(autogenFilter != SVGA3D_TEX_FILTER_FLATCUBIC);
- Assert(autogenFilter != SVGA3D_TEX_FILTER_GAUSSIANCUBIC);
- pSurface->pMipmapLevels = (PVMSVGA3DMIPMAPLEVEL)RTMemAllocZ(cMipLevels * sizeof(VMSVGA3DMIPMAPLEVEL));
- AssertReturn(pSurface->pMipmapLevels, VERR_NO_MEMORY);
-
- for (uint32_t i=0; i < cMipLevels; i++)
- pSurface->pMipmapLevels[i].size = pMipLevelSize[i];
-
- pSurface->cbBlock = vmsvga3dSurfaceFormatSize(format);
+ PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
- switch (surfaceFlags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
+ switch (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)
{
case SVGA3D_SURFACE_CUBEMAP:
- Log(("SVGA3D_SURFACE_CUBEMAP\n"));
- pSurface->cFaces = 6;
+ AssertFailed(); /** @todo destroy SVGA3D_SURFACE_CUBEMAP */
break;
case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- Log(("SVGA3D_SURFACE_HINT_INDEXBUFFER\n"));
- /* else type unknown at this time; postpone buffer creation */
- break;
-
case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- Log(("SVGA3D_SURFACE_HINT_VERTEXBUFFER\n"));
- /* Type unknown at this time; postpone buffer creation */
+ if (pSurface->oglId.buffer != OPENGL_INVALID_ID)
+ {
+ pState->ext.glDeleteBuffers(1, &pSurface->oglId.buffer);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ }
break;
case SVGA3D_SURFACE_HINT_TEXTURE:
- Log(("SVGA3D_SURFACE_HINT_TEXTURE\n"));
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ if (pSurface->oglId.texture != OPENGL_INVALID_ID)
+ {
+ glDeleteTextures(1, &pSurface->oglId.texture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ }
break;
case SVGA3D_SURFACE_HINT_RENDERTARGET:
- Log(("SVGA3D_SURFACE_HINT_RENDERTARGET\n"));
- break;
-
case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- Log(("SVGA3D_SURFACE_HINT_DEPTHSTENCIL\n"));
+ case SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_HINT_TEXTURE: /** @todo actual texture surface not supported */
+ if (pSurface->oglId.renderbuffer != OPENGL_INVALID_ID)
+ {
+ pState->ext.glDeleteRenderbuffers(1, &pSurface->oglId.renderbuffer);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ }
break;
default:
- /* Unknown; decide later. */
+ AssertMsg(!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface), ("type=%x\n", (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)));
break;
}
-
- /* Allocate buffer to hold the surface data until we can move it into a D3D object */
- for (uint32_t iFace=0; iFace < pSurface->cFaces; iFace++)
- {
- for (uint32_t i=0; i < pSurface->faces[iFace].numMipLevels; i++)
- {
- uint32_t idx = i + iFace * pSurface->faces[0].numMipLevels;
-
- Log(("vmsvga3dSurfaceDefine: face %d mip level %d (%d,%d,%d)\n", iFace, i, pSurface->pMipmapLevels[idx].size.width, pSurface->pMipmapLevels[idx].size.height, pSurface->pMipmapLevels[idx].size.depth));
- Log(("vmsvga3dSurfaceDefine: cbPitch=%x cbBlock=%x \n", pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width, pSurface->cbBlock));
-
- pSurface->pMipmapLevels[idx].cbSurfacePitch = pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width;
- pSurface->pMipmapLevels[idx].cbSurface = pSurface->pMipmapLevels[idx].cbSurfacePitch * pSurface->pMipmapLevels[idx].size.height * pSurface->pMipmapLevels[idx].size.depth;
- pSurface->pMipmapLevels[idx].pSurfaceData = RTMemAllocZ(pSurface->pMipmapLevels[idx].cbSurface);
- AssertReturn(pSurface->pMipmapLevels[idx].pSurfaceData, VERR_NO_MEMORY);
- }
- }
- return VINF_SUCCESS;
}
-int vmsvga3dSurfaceDestroy(PVGASTATE pThis, uint32_t sid)
-{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- AssertReturn(pState, VERR_NO_MEMORY);
-
- if ( sid < pState->cSurfaces
- && pState->papSurfaces[sid]->id == sid)
- {
- PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
- PVMSVGA3DCONTEXT pContext;
-
- Log(("vmsvga3dSurfaceDestroy id %x\n", sid));
-
-#if 1 /* Windows is doing this, guess it makes sense here as well... */
- /* Check all contexts if this surface is used as a render target or active texture. */
- for (uint32_t cid = 0; cid < pState->cContexts; cid++)
- {
- pContext = pState->papContexts[cid];
- if (pContext->id == cid)
- {
- for (uint32_t i = 0; i < RT_ELEMENTS(pContext->aSidActiveTexture); i++)
- if (pContext->aSidActiveTexture[i] == sid)
- pContext->aSidActiveTexture[i] = SVGA3D_INVALID_ID;
- if (pContext->sidRenderTarget == sid)
- pContext->sidRenderTarget = SVGA3D_INVALID_ID;
- }
- }
-#endif
-
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- pContext = &pState->SharedCtx;
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#else
- /* @todo stricter checks for associated context */
- uint32_t cid = pSurface->idAssociatedContext;
- if ( cid <= pState->cContexts
- && pState->papContexts[cid]->id == cid)
- {
- pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
- }
- /* If there is a GL buffer or something associated with the surface, we
- really need something here, so pick any active context. */
- else if (pSurface->oglId.buffer != OPENGL_INVALID_ID)
- {
- for (cid = 0; cid < pState->cContexts; cid++)
- {
- if (pState->papContexts[cid]->id == cid)
- {
- pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
- break;
- }
- }
- AssertReturn(pContext, VERR_INTERNAL_ERROR); /* otherwise crashes/fails; create temp context if this ever triggers! */
- }
-#endif
-
- switch (pSurface->flags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
- {
- case SVGA3D_SURFACE_CUBEMAP:
- AssertFailed(); /* @todo */
- break;
-
- case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- if (pSurface->oglId.buffer != OPENGL_INVALID_ID)
- {
- pState->ext.glDeleteBuffers(1, &pSurface->oglId.buffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- break;
-
- case SVGA3D_SURFACE_HINT_TEXTURE:
- case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
- if (pSurface->oglId.texture != OPENGL_INVALID_ID)
- {
- glDeleteTextures(1, &pSurface->oglId.texture);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- break;
-
- case SVGA3D_SURFACE_HINT_RENDERTARGET:
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_HINT_TEXTURE: /* @todo actual texture surface not supported */
- if (pSurface->oglId.renderbuffer != OPENGL_INVALID_ID)
- {
- pState->ext.glDeleteRenderbuffers(1, &pSurface->oglId.renderbuffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- break;
-
- default:
- break;
- }
-
- if (pSurface->pMipmapLevels)
- {
- for (uint32_t face=0; face < pSurface->cFaces; face++)
- {
- for (uint32_t i=0; i < pSurface->faces[face].numMipLevels; i++)
- {
- uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
- if (pSurface->pMipmapLevels[idx].pSurfaceData)
- RTMemFree(pSurface->pMipmapLevels[idx].pSurfaceData);
- }
- }
- RTMemFree(pSurface->pMipmapLevels);
- }
-
- memset(pSurface, 0, sizeof(*pSurface));
- pSurface->id = SVGA3D_INVALID_ID;
- }
- else
- AssertFailedReturn(VERR_INVALID_PARAMETER);
-
- return VINF_SUCCESS;
-}
int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfaceImageId src, uint32_t cCopyBoxes, SVGA3dCopyBox *pBox)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
uint32_t sidSrc = src.sid;
uint32_t sidDest = dest.sid;
int rc = VINF_SUCCESS;
AssertReturn(pState, VERR_NO_MEMORY);
- AssertReturn(sidSrc < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
+ Assert(sidSrc < SVGA3D_MAX_SURFACE_IDS);
AssertReturn(sidSrc < pState->cSurfaces && pState->papSurfaces[sidSrc]->id == sidSrc, VERR_INVALID_PARAMETER);
- AssertReturn(sidDest < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
+ Assert(sidDest < SVGA3D_MAX_SURFACE_IDS);
AssertReturn(sidDest < pState->cSurfaces && pState->papSurfaces[sidDest]->id == sidDest, VERR_INVALID_PARAMETER);
for (uint32_t i = 0; i < cCopyBoxes; i++)
@@ -2942,16 +1899,16 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
srcBox.z = pBox[i].srcz;
srcBox.w = pBox[i].w;
srcBox.h = pBox[i].h;
- srcBox.d = pBox[i].z;
+ srcBox.d = pBox[i].z; /* XXX what about pBox[i].d? */
destBox.x = pBox[i].x;
destBox.y = pBox[i].y;
destBox.z = pBox[i].z;
destBox.w = pBox[i].w;
destBox.h = pBox[i].h;
- destBox.z = pBox[i].z;
+ destBox.z = pBox[i].z; /* XXX initializing destBox.z again? What about pBox[i].d and destBox.d? */
- rc = vmsvga3dSurfaceStretchBlt(pThis, dest, destBox, src, srcBox, SVGA3D_STRETCH_BLT_LINEAR);
+ rc = vmsvga3dSurfaceStretchBlt(pThis, &dest, &destBox, &src, &srcBox, SVGA3D_STRETCH_BLT_LINEAR);
AssertRCReturn(rc, rc);
}
return VINF_SUCCESS;
@@ -2967,8 +1924,8 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
* @param pSurface The surface.
* @param pSave Where to save stuff.
*/
-static void vmsvga3dSetUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PVMSVGAPACKPARAMS pSave)
+void vmsvga3dOglSetUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PVMSVGAPACKPARAMS pSave)
{
/*
* Save (ignore errors, setting the defaults we want and avoids restore).
@@ -3042,8 +1999,8 @@ static void vmsvga3dSetUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pCon
* @param pSurface The surface.
* @param pSave Where stuff was saved.
*/
-static void vmsvga3dRestoreUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PCVMSVGAPACKPARAMS pSave)
+void vmsvga3dOglRestoreUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PCVMSVGAPACKPARAMS pSave)
{
NOREF(pSurface);
if (pSave->iAlignment != 1)
@@ -3067,20 +2024,27 @@ static void vmsvga3dRestoreUnpackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT
}
-/* Create D3D texture object for the specified surface. */
-static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext,
- PVMSVGA3DSURFACE pSurface)
+/**
+ * Create D3D/OpenGL texture object for the specified surface.
+ *
+ * Surfaces are created when needed.
+ *
+ * @param pState The VMSVGA3d state.
+ * @param pContext The context.
+ * @param idAssociatedContext Probably the same as pContext->id.
+ * @param pSurface The surface to create the texture for.
+ */
+int vmsvga3dBackCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext,
+ PVMSVGA3DSURFACE pSurface)
{
GLint activeTexture = 0;
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
uint32_t idPrevCtx = pState->idActiveContext;
pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
glGenTextures(1, &pSurface->oglId.texture);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- /* @todo Set the mip map generation filter settings. */
+ /** @todo Set the mip map generation filter settings. */
glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -3091,7 +2055,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContex
/* Set the unpacking parameters. */
VMSVGAPACKPARAMS SavedParams;
- vmsvga3dSetUnpackParams(pState, pContext, pSurface, &SavedParams);
+ vmsvga3dOglSetUnpackParams(pState, pContext, pSurface, &SavedParams);
/* Set the mipmap base and max level paramters. */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
@@ -3100,7 +2064,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContex
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
if (pSurface->fDirty)
- Log(("vmsvga3dCreateTexture: sync dirty texture\n"));
+ Log(("vmsvga3dBackCreateTexture: sync dirty texture\n"));
/* Always allocate and initialize all mipmap levels; non-initialized mipmap levels used as render targets cause failures. */
for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
@@ -3109,7 +2073,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContex
exposing random host memory to the guest and helps a with the fedora 21 surface
corruption issues (launchpad, background, search field, login). */
if (pSurface->pMipmapLevels[i].fDirty)
- Log(("vmsvga3dCreateTexture: sync dirty texture mipmap level %d (pitch %x)\n", i, pSurface->pMipmapLevels[i].cbSurfacePitch));
+ Log(("vmsvga3dBackCreateTexture: sync dirty texture mipmap level %d (pitch %x)\n", i, pSurface->pMipmapLevels[i].cbSurfacePitch));
glTexImage2D(GL_TEXTURE_2D,
i,
@@ -3128,92 +2092,40 @@ static int vmsvga3dCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContex
pSurface->fDirty = false;
/* Restore unpacking parameters. */
- vmsvga3dRestoreUnpackParams(pState, pContext, pSurface, &SavedParams);
+ vmsvga3dOglRestoreUnpackParams(pState, pContext, pSurface, &SavedParams);
/* Restore the old active texture. */
glBindTexture(GL_TEXTURE_2D, activeTexture);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
pSurface->flags |= SVGA3D_SURFACE_HINT_TEXTURE;
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- LogFlow(("vmsvga3dCreateTexture: sid=%x idAssociatedContext %#x -> %#x; oglId.texture=%#x\n",
- pSurface->id, pSurface->idAssociatedContext, idAssociatedContext, pSurface->oglId.texture));
- pSurface->idAssociatedContext = idAssociatedContext;
-#endif
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
if (idPrevCtx < pState->cContexts && pState->papContexts[idPrevCtx]->id == idPrevCtx)
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pState->papContexts[idPrevCtx]);
-#endif
return VINF_SUCCESS;
}
-int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dBox destBox,
- SVGA3dSurfaceImageId src, SVGA3dBox srcBox, SVGA3dStretchBltMode mode)
-{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- PVMSVGA3DSURFACE pSurfaceSrc;
- uint32_t sidSrc = src.sid;
- PVMSVGA3DSURFACE pSurfaceDest;
- uint32_t sidDest = dest.sid;
- int rc = VINF_SUCCESS;
- uint32_t cid;
- PVMSVGA3DCONTEXT pContext;
-
- AssertReturn(pState, VERR_NO_MEMORY);
- AssertReturn(sidSrc < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sidSrc < pState->cSurfaces && pState->papSurfaces[sidSrc]->id == sidSrc, VERR_INVALID_PARAMETER);
- AssertReturn(sidDest < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sidDest < pState->cSurfaces && pState->papSurfaces[sidDest]->id == sidDest, VERR_INVALID_PARAMETER);
-
- pSurfaceSrc = pState->papSurfaces[sidSrc];
- pSurfaceDest = pState->papSurfaces[sidDest];
- AssertReturn(pSurfaceSrc->faces[0].numMipLevels > src.mipmap, VERR_INVALID_PARAMETER);
- AssertReturn(pSurfaceDest->faces[0].numMipLevels > dest.mipmap, VERR_INVALID_PARAMETER);
-
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- Log(("vmsvga3dSurfaceStretchBlt: src sid=%x (%d,%d)(%d,%d) dest sid=%x (%d,%d)(%d,%d) mode=%x\n",
- src.sid, srcBox.x, srcBox.y, srcBox.x + srcBox.w, srcBox.y + srcBox.h,
- dest.sid, destBox.x, destBox.y, destBox.x + destBox.w, destBox.y + destBox.h, mode));
- cid = SVGA3D_INVALID_ID;
- pContext = &pState->SharedCtx;
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#else
- Log(("vmsvga3dSurfaceStretchBlt: src sid=%x cid=%x (%d,%d)(%d,%d) dest sid=%x cid=%x (%d,%d)(%d,%d) mode=%x\n",
- src.sid, pSurfaceSrc->idAssociatedContext, srcBox.x, srcBox.y, srcBox.x + srcBox.w, srcBox.y + srcBox.h,
- dest.sid, pSurfaceDest->idAssociatedContext, destBox.x, destBox.y, destBox.x + destBox.w, destBox.y + destBox.h, mode));
-
- /* @todo stricter checks for associated context */
- cid = pSurfaceDest->idAssociatedContext;
- if (cid == SVGA3D_INVALID_ID)
- cid = pSurfaceSrc->idAssociatedContext;
-
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSurfaceStretchBlt invalid context id!\n"));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
-
- if (pSurfaceSrc->oglId.texture == OPENGL_INVALID_ID)
- {
- /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
- Log(("vmsvga3dSurfaceStretchBlt: unknown src surface id=%x type=%d format=%d -> create texture\n", sidSrc, pSurfaceSrc->flags, pSurfaceSrc->format));
- rc = vmsvga3dCreateTexture(pState, pContext, cid, pSurfaceSrc);
- AssertRCReturn(rc, rc);
- }
-
- if (pSurfaceDest->oglId.texture == OPENGL_INVALID_ID)
- {
- /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
- Log(("vmsvga3dSurfaceStretchBlt: unknown dest surface id=%x type=%d format=%d -> create texture\n", sidDest, pSurfaceDest->flags, pSurfaceDest->format));
- rc = vmsvga3dCreateTexture(pState, pContext, cid, pSurfaceDest);
- AssertRCReturn(rc, rc);
- }
+/**
+ * Backend worker for implementing SVGA_3D_CMD_SURFACE_STRETCHBLT.
+ *
+ * @returns VBox status code.
+ * @param pThis The VGA device instance.
+ * @param pState The VMSVGA3d state.
+ * @param pDstSurface The destination host surface.
+ * @param uDstMipmap The destination mipmap level (valid).
+ * @param pDstBox The destination box.
+ * @param pSrcSurface The source host surface.
+ * @param uSrcMipmap The source mimap level (valid).
+ * @param pSrcBox The source box.
+ * @param enmMode The strecht blt mode .
+ * @param pContext The VMSVGA3d context (already current for OGL).
+ */
+int vmsvga3dBackSurfaceStretchBlt(PVGASTATE pThis, PVMSVGA3DSTATE pState,
+ PVMSVGA3DSURFACE pDstSurface, uint32_t uDstMipmap, SVGA3dBox const *pDstBox,
+ PVMSVGA3DSURFACE pSrcSurface, uint32_t uSrcMipmap, SVGA3dBox const *pSrcBox,
+ SVGA3dStretchBltMode enmMode, PVMSVGA3DCONTEXT pContext)
+{
/* Activate the read and draw framebuffer objects. */
pState->ext.glBindFramebuffer(GL_READ_FRAMEBUFFER, pContext->idReadFramebuffer);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -3222,42 +2134,42 @@ int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3d
/* Bind the source and destination objects to the right place. */
pState->ext.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- pSurfaceSrc->oglId.texture, src.mipmap);
+ pSrcSurface->oglId.texture, uSrcMipmap);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
pState->ext.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- pSurfaceDest->oglId.texture, dest.mipmap);
+ pDstSurface->oglId.texture, uDstMipmap);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- Log(("src conv. (%d,%d)(%d,%d); dest conv (%d,%d)(%d,%d)\n", srcBox.x, D3D_TO_OGL_Y_COORD(pSurfaceSrc, srcBox.y + srcBox.h),
- srcBox.x + srcBox.w, D3D_TO_OGL_Y_COORD(pSurfaceSrc, srcBox.y), destBox.x, D3D_TO_OGL_Y_COORD(pSurfaceDest, destBox.y + destBox.h),
- destBox.x + destBox.w, D3D_TO_OGL_Y_COORD(pSurfaceDest, destBox.y)));
+ Log(("src conv. (%d,%d)(%d,%d); dest conv (%d,%d)(%d,%d)\n", pSrcBox->x, D3D_TO_OGL_Y_COORD(pSrcSurface, pSrcBox->y + pSrcBox->h),
+ pSrcBox->x + pSrcBox->w, D3D_TO_OGL_Y_COORD(pSrcSurface, pSrcBox->y), pDstBox->x, D3D_TO_OGL_Y_COORD(pDstSurface, pDstBox->y + pDstBox->h),
+ pDstBox->x + pDstBox->w, D3D_TO_OGL_Y_COORD(pDstSurface, pDstBox->y)));
- pState->ext.glBlitFramebuffer(srcBox.x,
+ pState->ext.glBlitFramebuffer(pSrcBox->x,
#ifdef MANUAL_FLIP_SURFACE_DATA
- D3D_TO_OGL_Y_COORD(pSurfaceSrc, srcBox.y + srcBox.h), /* inclusive */
+ D3D_TO_OGL_Y_COORD(pSrcSurface, pSrcBox->y + pSrcBox->h), /* inclusive */
#else
- srcBox.y,
+ pSrcBox->y,
#endif
- srcBox.x + srcBox.w, /* exclusive. */
+ pSrcBox->x + pSrcBox->w, /* exclusive. */
#ifdef MANUAL_FLIP_SURFACE_DATA
- D3D_TO_OGL_Y_COORD(pSurfaceSrc, srcBox.y), /* exclusive */
+ D3D_TO_OGL_Y_COORD(pSrcSurface, pSrcBox->y), /* exclusive */
#else
- srcBox.y + srcBox.h,
+ pSrcBox->y + pSrcBox->h,
#endif
- destBox.x,
+ pDstBox->x,
#ifdef MANUAL_FLIP_SURFACE_DATA
- D3D_TO_OGL_Y_COORD(pSurfaceDest, destBox.y + destBox.h), /* inclusive. */
+ D3D_TO_OGL_Y_COORD(pDstSurface, pDstBox->y + pDstBox->h), /* inclusive. */
#else
- destBox.y,
+ pDstBox->y,
#endif
- destBox.x + destBox.w, /* exclusive. */
+ pDstBox->x + pDstBox->w, /* exclusive. */
#ifdef MANUAL_FLIP_SURFACE_DATA
- D3D_TO_OGL_Y_COORD(pSurfaceDest, destBox.y), /* exclusive */
+ D3D_TO_OGL_Y_COORD(pDstSurface, pDstBox->y), /* exclusive */
#else
- destBox.y + destBox.h,
+ pDstBox->y + pDstBox->h,
#endif
GL_COLOR_BUFFER_BIT,
- (mode == SVGA3D_STRETCH_BLT_POINT) ? GL_NEAREST : GL_LINEAR);
+ (enmMode == SVGA3D_STRETCH_BLT_POINT) ? GL_NEAREST : GL_LINEAR);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
/* Reset the frame buffer association */
@@ -3276,8 +2188,8 @@ int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3d
* @param pSurface The surface.
* @param pSave Where to save stuff.
*/
-static void vmsvga3dSetPackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PVMSVGAPACKPARAMS pSave)
+void vmsvga3dOglSetPackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PVMSVGAPACKPARAMS pSave)
{
/*
* Save (ignore errors, setting the defaults we want and avoids restore).
@@ -3351,8 +2263,8 @@ static void vmsvga3dSetPackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pConte
* @param pSurface The surface.
* @param pSave Where stuff was saved.
*/
-static void vmsvga3dRestorePackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
- PCVMSVGAPACKPARAMS pSave)
+void vmsvga3dOglRestorePackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface,
+ PCVMSVGAPACKPARAMS pSave)
{
NOREF(pSurface);
if (pSave->iAlignment != 1)
@@ -3376,342 +2288,229 @@ static void vmsvga3dRestorePackParams(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pC
}
-int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
- uint32_t cCopyBoxes, SVGA3dCopyBox *pBoxes)
+/**
+ * Backend worker for implementing SVGA_3D_CMD_SURFACE_DMA that copies one box.
+ *
+ * @returns Failure status code or @a rc.
+ * @param pThis The VGA device instance data.
+ * @param pState The VMSVGA3d state.
+ * @param pSurface The host surface.
+ * @param uHostMipmap The host mipmap level (valid).
+ * @param GuestPtr The guest pointer.
+ * @param cbSrcPitch The guest (?) pitch.
+ * @param transfer The transfer direction.
+ * @param pBox The box to copy.
+ * @param pContext The context (for OpenGL).
+ * @param rc The current rc for all boxes.
+ * @param iBox The current box number (for Direct 3D).
+ */
+int vmsvga3dBackSurfaceDMACopyBox(PVGASTATE pThis, PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, uint32_t uHostMipmap,
+ SVGAGuestPtr GuestPtr, uint32_t cbSrcPitch, SVGA3dTransferType transfer,
+ SVGA3dCopyBox const *pBox, PVMSVGA3DCONTEXT pContext, int rc, int iBox)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- PVMSVGA3DSURFACE pSurface;
- PVMSVGA3DMIPMAPLEVEL pMipLevel;
- uint32_t sid = host.sid;
- int rc = VINF_SUCCESS;
-
- AssertReturn(pState, VERR_NO_MEMORY);
- AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sid < pState->cSurfaces && pState->papSurfaces[sid]->id == sid, VERR_INVALID_PARAMETER);
-
- pSurface = pState->papSurfaces[sid];
- AssertReturn(pSurface->faces[0].numMipLevels > host.mipmap, VERR_INVALID_PARAMETER);
- pMipLevel = &pSurface->pMipmapLevels[host.mipmap];
-
- if (pSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE)
- Log(("vmsvga3dSurfaceDMA TEXTURE guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
- else
- Log(("vmsvga3dSurfaceDMA guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
+ PVMSVGA3DMIPMAPLEVEL pMipLevel = &pSurface->pMipmapLevels[uHostMipmap];
- if (pSurface->oglId.texture == OPENGL_INVALID_ID)
+ switch (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)
{
- AssertReturn(pSurface->pMipmapLevels[host.mipmap].pSurfaceData, VERR_INTERNAL_ERROR);
-
- for (unsigned i = 0; i < cCopyBoxes; i++)
- {
- unsigned uDestOffset;
- unsigned cbSrcPitch;
- uint8_t *pBufferStart;
-
- Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, pBoxes[i].srcx, pBoxes[i].srcy, pBoxes[i].srcz, pBoxes[i].w, pBoxes[i].h, pBoxes[i].d, pBoxes[i].x, pBoxes[i].y));
- /* Apparently we're supposed to clip it (gmr test sample) */
- if (pBoxes[i].x + pBoxes[i].w > pMipLevel->size.width)
- pBoxes[i].w = pMipLevel->size.width - pBoxes[i].x;
- if (pBoxes[i].y + pBoxes[i].h > pMipLevel->size.height)
- pBoxes[i].h = pMipLevel->size.height - pBoxes[i].y;
- if (pBoxes[i].z + pBoxes[i].d > pMipLevel->size.depth)
- pBoxes[i].d = pMipLevel->size.depth - pBoxes[i].z;
-
- if ( !pBoxes[i].w
- || !pBoxes[i].h
- || !pBoxes[i].d
- || pBoxes[i].x > pMipLevel->size.width
- || pBoxes[i].y > pMipLevel->size.height
- || pBoxes[i].z > pMipLevel->size.depth)
- {
- Log(("Empty box; skip\n"));
- continue;
- }
-
- uDestOffset = pBoxes[i].x * pSurface->cbBlock + pBoxes[i].y * pMipLevel->cbSurfacePitch + pBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
- AssertReturn(uDestOffset + pBoxes[i].w * pSurface->cbBlock * pBoxes[i].h * pBoxes[i].d <= pMipLevel->cbSurface, VERR_INTERNAL_ERROR);
-
- cbSrcPitch = (guest.pitch == 0) ? pBoxes[i].w * pSurface->cbBlock : guest.pitch;
-#ifdef MANUAL_FLIP_SURFACE_DATA
- pBufferStart = (uint8_t *)pMipLevel->pSurfaceData
- + pBoxes[i].x * pSurface->cbBlock
- + pMipLevel->cbSurface - pBoxes[i].y * pMipLevel->cbSurfacePitch
- - pMipLevel->cbSurfacePitch; /* flip image during copy */
-#else
- pBufferStart = (uint8_t *)pMipLevel->pSurfaceData + uDestOffset;
-#endif
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- pBufferStart,
-#ifdef MANUAL_FLIP_SURFACE_DATA
- -(int32_t)pMipLevel->cbSurfacePitch,
-#else
- (int32_t)pMipLevel->cbSurfacePitch,
-#endif
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + (pBoxes[i].srcy + pBoxes[i].srcz * pBoxes[i].h) * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].d * pBoxes[i].h);
-
- Log4(("first line:\n%.*Rhxd\n", pMipLevel->cbSurface, pMipLevel->pSurfaceData));
-
- AssertRC(rc);
- }
- pSurface->pMipmapLevels[host.mipmap].fDirty = true;
- pSurface->fDirty = true;
- }
- else
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ case SVGA3D_SURFACE_HINT_TEXTURE:
+ case SVGA3D_SURFACE_HINT_RENDERTARGET:
{
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
-#else
- /* @todo stricter checks for associated context */
- uint32_t cid = pSurface->idAssociatedContext;
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSurfaceDMA invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
-#endif
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-
- for (unsigned i = 0; i < cCopyBoxes; i++)
- {
- bool fVertex = false;
- unsigned cbSrcPitch;
-
- /* Apparently we're supposed to clip it (gmr test sample) */
- if (pBoxes[i].x + pBoxes[i].w > pMipLevel->size.width)
- pBoxes[i].w = pMipLevel->size.width - pBoxes[i].x;
- if (pBoxes[i].y + pBoxes[i].h > pMipLevel->size.height)
- pBoxes[i].h = pMipLevel->size.height - pBoxes[i].y;
- if (pBoxes[i].z + pBoxes[i].d > pMipLevel->size.depth)
- pBoxes[i].d = pMipLevel->size.depth - pBoxes[i].z;
-
- Assert((pBoxes[i].d == 1 || pBoxes[i].d == 0) && pBoxes[i].z == 0);
-
- if ( !pBoxes[i].w
- || !pBoxes[i].h
- || pBoxes[i].x > pMipLevel->size.width
- || pBoxes[i].y > pMipLevel->size.height)
- {
- Log(("Empty box; skip\n"));
- continue;
- }
-
- Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, pBoxes[i].srcx, pBoxes[i].srcy, pBoxes[i].srcz, pBoxes[i].w, pBoxes[i].h, pBoxes[i].d, pBoxes[i].x, pBoxes[i].y));
-
- cbSrcPitch = (guest.pitch == 0) ? pBoxes[i].w * pSurface->cbBlock : guest.pitch;
-
- switch (pSurface->flags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
- {
- case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
- case SVGA3D_SURFACE_HINT_TEXTURE:
- case SVGA3D_SURFACE_HINT_RENDERTARGET:
- {
- uint32_t cbSurfacePitch;
- uint8_t *pDoubleBuffer, *pBufferStart;
- unsigned uDestOffset = 0;
+ uint32_t cbSurfacePitch;
+ uint8_t *pDoubleBuffer, *pBufferStart;
+ unsigned uDestOffset = 0;
- pDoubleBuffer = (uint8_t *)RTMemAlloc(pMipLevel->cbSurface);
- AssertReturn(pDoubleBuffer, VERR_NO_MEMORY);
+ pDoubleBuffer = (uint8_t *)RTMemAlloc(pMipLevel->cbSurface);
+ AssertReturn(pDoubleBuffer, VERR_NO_MEMORY);
- if (transfer == SVGA3D_READ_HOST_VRAM)
- {
- GLint activeTexture;
+ if (transfer == SVGA3D_READ_HOST_VRAM)
+ {
+ GLint activeTexture;
- /* Must bind texture to the current context in order to read it. */
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ /* Must bind texture to the current context in order to read it. */
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* Set row length and alignment of the input data. */
- VMSVGAPACKPARAMS SavedParams;
- vmsvga3dSetPackParams(pState, pContext, pSurface, &SavedParams);
+ /* Set row length and alignment of the input data. */
+ VMSVGAPACKPARAMS SavedParams;
+ vmsvga3dOglSetPackParams(pState, pContext, pSurface, &SavedParams);
- glGetTexImage(GL_TEXTURE_2D,
- host.mipmap,
- pSurface->formatGL,
- pSurface->typeGL,
- pDoubleBuffer);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ glGetTexImage(GL_TEXTURE_2D,
+ uHostMipmap,
+ pSurface->formatGL,
+ pSurface->typeGL,
+ pDoubleBuffer);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- vmsvga3dRestorePackParams(pState, pContext, pSurface, &SavedParams);
+ vmsvga3dOglRestorePackParams(pState, pContext, pSurface, &SavedParams);
- /* Restore the old active texture. */
- glBindTexture(GL_TEXTURE_2D, activeTexture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ /* Restore the old active texture. */
+ glBindTexture(GL_TEXTURE_2D, activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- uDestOffset = pBoxes[i].x * pSurface->cbBlock + pBoxes[i].y * pMipLevel->cbSurfacePitch;
- AssertReturnStmt( uDestOffset + pBoxes[i].w * pSurface->cbBlock + (pBoxes[i].h - 1) * pMipLevel->cbSurfacePitch
- <= pMipLevel->cbSurface,
- RTMemFree(pDoubleBuffer),
- VERR_INTERNAL_ERROR);
+ uDestOffset = pBox->x * pSurface->cbBlock + pBox->y * pMipLevel->cbSurfacePitch;
+ AssertReturnStmt( uDestOffset + pBox->w * pSurface->cbBlock + (pBox->h - 1) * pMipLevel->cbSurfacePitch
+ <= pMipLevel->cbSurface,
+ RTMemFree(pDoubleBuffer),
+ VERR_INTERNAL_ERROR);
- cbSurfacePitch = pMipLevel->cbSurfacePitch;
+ cbSurfacePitch = pMipLevel->cbSurfacePitch;
#ifdef MANUAL_FLIP_SURFACE_DATA
- pBufferStart = pDoubleBuffer
- + pBoxes[i].x * pSurface->cbBlock
- + pMipLevel->cbSurface - pBoxes[i].y * cbSurfacePitch
- - cbSurfacePitch; /* flip image during copy */
+ pBufferStart = pDoubleBuffer
+ + pBox->x * pSurface->cbBlock
+ + pMipLevel->cbSurface - pBox->y * cbSurfacePitch
+ - cbSurfacePitch; /* flip image during copy */
#else
- pBufferStart = pDoubleBuffer + uDestOffset;
+ pBufferStart = pDoubleBuffer + uDestOffset;
#endif
- }
- else
- {
- cbSurfacePitch = pBoxes[i].w * pSurface->cbBlock;
+ }
+ else
+ {
+ cbSurfacePitch = pBox->w * pSurface->cbBlock;
#ifdef MANUAL_FLIP_SURFACE_DATA
- pBufferStart = pDoubleBuffer + cbSurfacePitch * pBoxes[i].h - cbSurfacePitch; /* flip image during copy */
+ pBufferStart = pDoubleBuffer + cbSurfacePitch * pBox->h - cbSurfacePitch; /* flip image during copy */
#else
- pBufferStart = pDoubleBuffer;
+ pBufferStart = pDoubleBuffer;
#endif
- }
+ }
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- pBufferStart,
+ rc = vmsvgaGMRTransfer(pThis,
+ transfer,
+ pBufferStart,
#ifdef MANUAL_FLIP_SURFACE_DATA
- -(int32_t)cbSurfacePitch,
+ -(int32_t)cbSurfacePitch,
#else
- (int32_t)cbSurfacePitch,
+ (int32_t)cbSurfacePitch,
#endif
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + pBoxes[i].srcy * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].h);
- AssertRC(rc);
-
- /* Update the opengl surface data. */
- if (transfer == SVGA3D_WRITE_HOST_VRAM)
- {
- GLint activeTexture = 0;
+ GuestPtr,
+ pBox->srcx * pSurface->cbBlock + pBox->srcy * cbSrcPitch,
+ cbSrcPitch,
+ pBox->w * pSurface->cbBlock,
+ pBox->h);
+ AssertRC(rc);
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ /* Update the opengl surface data. */
+ if (transfer == SVGA3D_WRITE_HOST_VRAM)
+ {
+ GLint activeTexture = 0;
- /* Must bind texture to the current context in order to change it. */
- glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- Log(("vmsvga3dSurfaceDMA: copy texture mipmap level %d (pitch %x)\n", host.mipmap, pMipLevel->cbSurfacePitch));
+ /* Must bind texture to the current context in order to change it. */
+ glBindTexture(GL_TEXTURE_2D, pSurface->oglId.texture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* Set row length and alignment of the input data. */
- VMSVGAPACKPARAMS SavedParams;
- vmsvga3dSetUnpackParams(pState, pContext, pSurface, &SavedParams); /** @todo do we need to set ROW_LENGTH to w here? */
+ Log(("vmsvga3dSurfaceDMA: copy texture mipmap level %d (pitch %x)\n", uHostMipmap, pMipLevel->cbSurfacePitch));
- glTexSubImage2D(GL_TEXTURE_2D,
- host.mipmap,
- pBoxes[i].x,
- pBoxes[i].y,
- pBoxes[i].w,
- pBoxes[i].h,
- pSurface->formatGL,
- pSurface->typeGL,
- pDoubleBuffer);
+ /* Set row length and alignment of the input data. */
+ VMSVGAPACKPARAMS SavedParams;
+ vmsvga3dOglSetUnpackParams(pState, pContext, pSurface, &SavedParams); /** @todo do we need to set ROW_LENGTH to w here? */
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ glTexSubImage2D(GL_TEXTURE_2D,
+ uHostMipmap,
+ pBox->x,
+ pBox->y,
+ pBox->w,
+ pBox->h,
+ pSurface->formatGL,
+ pSurface->typeGL,
+ pDoubleBuffer);
- /* Restore old values. */
- vmsvga3dRestoreUnpackParams(pState, pContext, pSurface, &SavedParams);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* Restore the old active texture. */
- glBindTexture(GL_TEXTURE_2D, activeTexture);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- }
+ /* Restore old values. */
+ vmsvga3dOglRestoreUnpackParams(pState, pContext, pSurface, &SavedParams);
- Log4(("first line:\n%.*Rhxd\n", pBoxes[i].w * pSurface->cbBlock, pDoubleBuffer));
+ /* Restore the old active texture. */
+ glBindTexture(GL_TEXTURE_2D, activeTexture);
+ VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ }
- /* Free the double buffer. */
- RTMemFree(pDoubleBuffer);
- break;
- }
+ Log4(("first line:\n%.*Rhxd\n", pBox->w * pSurface->cbBlock, pDoubleBuffer));
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- AssertFailed(); /* @todo */
- break;
+ /* Free the double buffer. */
+ RTMemFree(pDoubleBuffer);
+ break;
+ }
- case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- {
- Assert(pBoxes[i].h == 1);
+ case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
+ AssertFailed(); /** @todo DMA SVGA3D_SURFACE_HINT_DEPTHSTENCIL */
+ break;
- VMSVGA3D_CLEAR_GL_ERRORS();
- pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pSurface->oglId.buffer);
- if (VMSVGA3D_GL_IS_SUCCESS(pContext))
- {
- GLenum enmGlTransfer = (transfer == SVGA3D_READ_HOST_VRAM) ? GL_READ_ONLY : GL_WRITE_ONLY;
- uint8_t *pbData = (uint8_t *)pState->ext.glMapBuffer(GL_ARRAY_BUFFER, enmGlTransfer);
- if (RT_LIKELY(pbData != NULL))
- {
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ {
+ Assert(pBox->h == 1);
+
+ VMSVGA3D_CLEAR_GL_ERRORS();
+ pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pSurface->oglId.buffer);
+ if (VMSVGA3D_GL_IS_SUCCESS(pContext))
+ {
+ GLenum enmGlTransfer = (transfer == SVGA3D_READ_HOST_VRAM) ? GL_READ_ONLY : GL_WRITE_ONLY;
+ uint8_t *pbData = (uint8_t *)pState->ext.glMapBuffer(GL_ARRAY_BUFFER, enmGlTransfer);
+ if (RT_LIKELY(pbData != NULL))
+ {
#if defined(VBOX_STRICT) && defined(RT_OS_DARWIN)
- GLint cbStrictBufSize;
- glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &cbStrictBufSize);
- Assert(VMSVGA3D_GL_IS_SUCCESS(pContext));
-# ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- AssertMsg(cbStrictBufSize >= (int32_t)pMipLevel->cbSurface,
- ("cbStrictBufSize=%#x cbSurface=%#x pContext->id=%#x\n", (uint32_t)cbStrictBufSize, pMipLevel->cbSurface, pContext->id));
-# else
- AssertMsg(cbStrictBufSize >= (int32_t)pMipLevel->cbSurface,
- ("cbStrictBufSize=%#x cbSurface=%#x isAssociatedContext=%#x pContext->id=%#x\n", (uint32_t)cbStrictBufSize, pMipLevel->cbSurface, pSurface->idAssociatedContext, pContext->id));
-# endif
+ GLint cbStrictBufSize;
+ glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &cbStrictBufSize);
+ Assert(VMSVGA3D_GL_IS_SUCCESS(pContext));
+ AssertMsg(cbStrictBufSize >= (int32_t)pMipLevel->cbSurface,
+ ("cbStrictBufSize=%#x cbSurface=%#x pContext->id=%#x\n", (uint32_t)cbStrictBufSize, pMipLevel->cbSurface, pContext->id));
#endif
- unsigned offDst = pBoxes[i].x * pSurface->cbBlock + pBoxes[i].y * pMipLevel->cbSurfacePitch;
- if (RT_LIKELY( offDst + pBoxes[i].w * pSurface->cbBlock + (pBoxes[i].h - 1) * pMipLevel->cbSurfacePitch
- <= pMipLevel->cbSurface))
- {
- Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (fVertex) ? "vertex" : "index",
- pBoxes[i].x, pBoxes[i].y, pBoxes[i].x + pBoxes[i].w, pBoxes[i].y + pBoxes[i].h));
-
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- pbData + offDst,
- pMipLevel->cbSurfacePitch,
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + pBoxes[i].srcy * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].h);
- AssertRC(rc);
-
- Log4(("first line:\n%.*Rhxd\n", cbSrcPitch, pbData));
- }
- else
- {
- AssertFailed();
- rc = VERR_INTERNAL_ERROR;
- }
-
- pState->ext.glUnmapBuffer(GL_ARRAY_BUFFER);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- else
- VMSVGA3D_GL_GET_AND_COMPLAIN(pState, pContext, ("glMapBuffer(GL_ARRAY_BUFFER, %#x) -> NULL\n", enmGlTransfer));
+ unsigned offDst = pBox->x * pSurface->cbBlock + pBox->y * pMipLevel->cbSurfacePitch;
+ if (RT_LIKELY( offDst + pBox->w * pSurface->cbBlock + (pBox->h - 1) * pMipLevel->cbSurfacePitch
+ <= pMipLevel->cbSurface))
+ {
+ Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK) == SVGA3D_SURFACE_HINT_VERTEXBUFFER ? "vertex" : "index",
+ pBox->x, pBox->y, pBox->x + pBox->w, pBox->y + pBox->h));
+
+ rc = vmsvgaGMRTransfer(pThis,
+ transfer,
+ pbData + offDst,
+ pMipLevel->cbSurfacePitch,
+ GuestPtr,
+ pBox->srcx * pSurface->cbBlock + pBox->srcy * cbSrcPitch,
+ cbSrcPitch,
+ pBox->w * pSurface->cbBlock,
+ pBox->h);
+ AssertRC(rc);
+
+ Log4(("first line:\n%.*Rhxd\n", cbSrcPitch, pbData));
}
else
- VMSVGA3D_GL_COMPLAIN(pState, pContext, ("glBindBuffer(GL_ARRAY_BUFFER, %#x)\n", pSurface->oglId.buffer));
- pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- break;
- }
+ {
+ AssertFailed();
+ rc = VERR_INTERNAL_ERROR;
+ }
- default:
- AssertFailed();
- break;
+ pState->ext.glUnmapBuffer(GL_ARRAY_BUFFER);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
}
+ else
+ VMSVGA3D_GL_GET_AND_COMPLAIN(pState, pContext, ("glMapBuffer(GL_ARRAY_BUFFER, %#x) -> NULL\n", enmGlTransfer));
}
+ else
+ VMSVGA3D_GL_COMPLAIN(pState, pContext, ("glBindBuffer(GL_ARRAY_BUFFER, %#x)\n", pSurface->oglId.buffer));
+ pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ break;
}
+
return rc;
}
+
int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect destRect, SVGA3dSurfaceImageId src, SVGASignedRect srcRect, uint32_t cRects, SVGASignedRect *pRect)
{
/* Requires SVGA_FIFO_CAP_SCREEN_OBJECT support */
@@ -3721,10 +2520,10 @@ int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect d
Log(("vmsvga3dSurfaceBlitToScreen: clipping rect %d (%d,%d)(%d,%d)\n", i, pRect[i].left, pRect[i].top, pRect[i].right, pRect[i].bottom));
}
- /* @todo Only screen 0 for now. */
+ /** @todo Only screen 0 for now. */
AssertReturn(dest == 0, VERR_INTERNAL_ERROR);
AssertReturn(src.mipmap == 0 && src.face == 0, VERR_INVALID_PARAMETER);
- /* @todo scaling */
+ /** @todo scaling */
AssertReturn(destRect.right - destRect.left == srcRect.right - srcRect.left && destRect.bottom - destRect.top == srcRect.bottom - srcRect.top, VERR_INVALID_PARAMETER);
if (cRects == 0)
@@ -3766,7 +2565,7 @@ int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect d
dst.ptr.offset = 0;
dst.pitch = pThis->svga.cbScanline;
- /* @todo merge into one SurfaceDMA call */
+ /** @todo merge into one SurfaceDMA call */
for (uint32_t i = 0; i < cRects; i++)
{
/* The clipping rectangle is relative to the top-left corner of srcRect & destRect. Adjust here. */
@@ -3791,7 +2590,7 @@ int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect d
int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter filter)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pSurface;
int rc = VINF_SUCCESS;
PVMSVGA3DCONTEXT pContext;
@@ -3803,9 +2602,6 @@ int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter f
AssertReturn(sid < pState->cSurfaces && pState->papSurfaces[sid]->id == sid, VERR_INVALID_PARAMETER);
pSurface = pState->papSurfaces[sid];
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- AssertReturn(pSurface->idAssociatedContext != SVGA3D_INVALID_ID, VERR_INTERNAL_ERROR);
-#endif
Assert(filter != SVGA3D_TEX_FILTER_FLATCUBIC);
Assert(filter != SVGA3D_TEX_FILTER_GAUSSIANCUBIC);
@@ -3813,34 +2609,20 @@ int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter f
Log(("vmsvga3dGenerateMipmaps: sid=%x filter=%d\n", sid, filter));
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
cid = SVGA3D_INVALID_ID;
pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#else
- /* @todo stricter checks for associated context */
- cid = pSurface->idAssociatedContext;
-
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dGenerateMipmaps invalid context id!\n"));
- return VERR_INVALID_PARAMETER;
- }
- pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
if (pSurface->oglId.texture == OPENGL_INVALID_ID)
{
/* Unknown surface type; turn it into a texture. */
Log(("vmsvga3dGenerateMipmaps: unknown src surface id=%x type=%d format=%d -> create texture\n", sid, pSurface->flags, pSurface->format));
- rc = vmsvga3dCreateTexture(pState, pContext, cid, pSurface);
+ rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pSurface);
AssertRCReturn(rc, rc);
}
else
{
- /* @todo new filter */
+ /** @todo new filter */
AssertFailed();
}
@@ -3864,7 +2646,7 @@ int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter f
int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3dCopyRect *pRect)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pSurface;
int rc = VINF_SUCCESS;
PVMSVGA3DCONTEXT pContext;
@@ -3875,44 +2657,17 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
AssertReturn(sid < pState->cSurfaces && pState->papSurfaces[sid]->id == sid, VERR_INVALID_PARAMETER);
pSurface = pState->papSurfaces[sid];
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- AssertReturn(pSurface->idAssociatedContext != SVGA3D_INVALID_ID, VERR_INTERNAL_ERROR);
-#endif
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
- /* @todo stricter checks for associated context */
Log(("vmsvga3dCommandPresent: sid=%x cRects=%d\n", sid, cRects));
for (uint32_t i=0; i < cRects; i++)
Log(("vmsvga3dCommandPresent: rectangle %d src=(%d,%d) (%d,%d)(%d,%d)\n", i, pRect[i].srcx, pRect[i].srcy, pRect[i].x, pRect[i].y, pRect[i].x + pRect[i].w, pRect[i].y + pRect[i].h));
pContext = &pState->SharedCtx;
-# ifdef VMSVGA3D_OGL_WITH_SHARED_CTX_EXPERIMENT_1
- if ( pSurface->idWeakContextAssociation < pState->cContexts
- && pState->papContexts[pSurface->idWeakContextAssociation]->id == pSurface->idWeakContextAssociation)
- pContext = pState->papContexts[pSurface->idWeakContextAssociation];
-# endif
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
cid = pContext->id;
-#else
- /* @todo stricter checks for associated context */
- cid = pSurface->idAssociatedContext;
- Log(("vmsvga3dCommandPresent: sid=%x cRects=%d cid=%x\n", sid, cRects, cid));
- for (uint32_t i=0; i < cRects; i++)
- {
- Log(("vmsvga3dCommandPresent: rectangle %d src=(%d,%d) (%d,%d)(%d,%d)\n", i, pRect[i].srcx, pRect[i].srcy, pRect[i].x, pRect[i].y, pRect[i].x + pRect[i].w, pRect[i].y + pRect[i].h));
- }
-
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dCommandPresent invalid context id!\n"));
- return VERR_INVALID_PARAMETER;
- }
- pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
VMSVGA3D_CLEAR_GL_ERRORS();
+#if 0 /* Can't make sense of this. SVGA3dCopyRect doesn't allow scaling. non-blit-cube path change to not use it. */
/*
* Source surface different size?
*/
@@ -3920,11 +2675,13 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
if ( pSurface->pMipmapLevels[0].size.width != pThis->svga.uWidth
|| pSurface->pMipmapLevels[0].size.height != pThis->svga.uHeight)
{
- float xMultiplier = (float)pSurface->pMipmapLevels[0].size.width / (float)pThis->svga.uWidth;
+ float xMultiplier = (float)pSurface->pMipmapLevels[0].size.width / (float)pThis->svga.uWidth;
float yMultiplier = (float)pSurface->pMipmapLevels[0].size.height / (float)pThis->svga.uHeight;
- LogFlow(("size (%d vs %d) (%d vs %d) multiplier (%d,%d)/100\n", pSurface->pMipmapLevels[0].size.width, pThis->svga.uWidth,
- pSurface->pMipmapLevels[0].size.height, pThis->svga.uHeight, (int)(xMultiplier * 100.0), (int)(yMultiplier * 100.0)));
+ LogFlow(("size (%d vs %d, %d vs %d) multiplier (" FLOAT_FMT_STR ", " FLOAT_FMT_STR ")\n",
+ pSurface->pMipmapLevels[0].size.width, pThis->svga.uWidth,
+ pSurface->pMipmapLevels[0].size.height, pThis->svga.uHeight,
+ FLOAT_FMT_ARGS(xMultiplier), FLOAT_FMT_ARGS(yMultiplier) ));
srcViewPort.x = (uint32_t)((float)pThis->svga.viewport.x * xMultiplier);
srcViewPort.y = (uint32_t)((float)pThis->svga.viewport.y * yMultiplier);
@@ -3943,9 +2700,10 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
SrcViewPortRect.xRight = srcViewPort.x + srcViewPort.cx;
SrcViewPortRect.yBottom = srcViewPort.y;
SrcViewPortRect.yTop = srcViewPort.y + srcViewPort.cy;
+#endif
-#ifndef RT_OS_DARWIN /* blit-cube fails in this path... */
+#if 0//ndef RT_OS_DARWIN /* blit-cube fails in this path... */
/*
* Note! this path is slightly faster than the glBlitFrameBuffer path below.
*/
@@ -4019,8 +2777,8 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
float left, right, top, bottom; /* Texture coordinates */
int vertexLeft, vertexRight, vertexTop, vertexBottom;
- pRect[i].srcx = RT_MAX(pRect[i].srcx, srcViewPort.x);
- pRect[i].srcy = RT_MAX(pRect[i].srcy, srcViewPort.y);
+ pRect[i].srcx = RT_MAX(pRect[i].srcx, (uint32_t)RT_MAX(srcViewPort.x, 0));
+ pRect[i].srcy = RT_MAX(pRect[i].srcy, (uint32_t)RT_MAX(srcViewPort.y, 0));
pRect[i].x = RT_MAX(pRect[i].x, pThis->svga.viewport.x) - pThis->svga.viewport.x;
pRect[i].y = RT_MAX(pRect[i].y, pThis->svga.viewport.y) - pThis->svga.viewport.y;
pRect[i].w = pThis->svga.viewport.cx;
@@ -4101,113 +2859,266 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
pState->ext.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pSurface->oglId.texture, 0 /* level 0 */);
VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* Blit the surface rectangle(s) to the back buffer. */
- if (cRects == 0)
+ /* Read the destination viewport specs in one go to try avoid some unnecessary update races. */
+ VMSVGAVIEWPORT const DstViewport = pThis->svga.viewport;
+ ASMCompilerBarrier(); /* paranoia */
+ Assert(DstViewport.yHighWC >= DstViewport.yLowWC);
+
+ /* If there are no recangles specified, just grab a screenful. */
+ SVGA3dCopyRect DummyRect;
+ if (cRects != 0)
+ { /* likely */ }
+ else
{
- Log(("view port (%d,%d)(%d,%d)\n", srcViewPort.x, srcViewPort.y, srcViewPort.cx, srcViewPort.cy));
- pState->ext.glBlitFramebuffer(srcViewPort.x,
- srcViewPort.y,
- srcViewPort.x + srcViewPort.cx, /* exclusive. */
- srcViewPort.y + srcViewPort.cy, /* exclusive. (reverse to flip the image) */
- 0,
- pThis->svga.viewport.cy, /* exclusive. */
- pThis->svga.viewport.cx, /* exclusive. */
- 0,
- GL_COLOR_BUFFER_BIT,
- GL_LINEAR);
- VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
+ /** @todo Find the usecase for this or check what the original device does.
+ * The original code was doing some scaling based on the surface
+ * size... */
+# ifdef DEBUG_bird
+ AssertMsgFailed(("No rects to present. Who is doing that and what do they actually expect?\n"));
+# endif
+ DummyRect.x = DummyRect.srcx = 0;
+ DummyRect.y = DummyRect.srcy = 0;
+ DummyRect.w = pThis->svga.uWidth;
+ DummyRect.h = pThis->svga.uHeight;
+ cRects = 1;
+ pRect = &DummyRect;
}
- else
+
+ /*
+ * Blit the surface rectangle(s) to the back buffer.
+ */
+ uint32_t const cxSurface = pSurface->pMipmapLevels[0].size.width;
+ uint32_t const cySurface = pSurface->pMipmapLevels[0].size.height;
+ for (uint32_t i = 0; i < cRects; i++)
{
- for (uint32_t i = 0; i < cRects; i++)
+ SVGA3dCopyRect ClippedRect = pRect[i];
+
+ /*
+ * Do some sanity checking and limit width and height, all so we
+ * don't need to think about wrap-arounds below.
+ */
+ if (RT_LIKELY( ClippedRect.w
+ && ClippedRect.x < VMSVGA_MAX_X
+ && ClippedRect.srcx < VMSVGA_MAX_X
+ && ClippedRect.h
+ && ClippedRect.y < VMSVGA_MAX_Y
+ && ClippedRect.srcy < VMSVGA_MAX_Y
+ ))
+ { /* likely */ }
+ else
+ continue;
+
+ if (RT_LIKELY(ClippedRect.w < VMSVGA_MAX_Y))
+ { /* likely */ }
+ else
+ ClippedRect.w = VMSVGA_MAX_Y;
+ if (RT_LIKELY(ClippedRect.w < VMSVGA_MAX_Y))
+ { /* likely */ }
+ else
+ ClippedRect.w = VMSVGA_MAX_Y;
+
+
+ /*
+ * Source surface clipping (paranoia). Straight forward.
+ */
+ if (RT_LIKELY(ClippedRect.srcx < cxSurface))
+ { /* likely */ }
+ else
+ continue;
+ if (RT_LIKELY(ClippedRect.srcx + ClippedRect.w <= cxSurface))
+ { /* likely */ }
+ else
{
-# ifdef RT_OS_DARWIN
- /* This works better... */
- RTRECT SrcRect;
- SrcRect.xLeft = pRect[i].srcx;
- SrcRect.xRight = pRect[i].srcx + pRect[i].w;
- SrcRect.yBottom = pRect[i].srcy;
- SrcRect.yTop = pRect[i].srcy + pRect[i].h;
- RTRECT DstRect; /* y flipped wrt source */
- DstRect.xLeft = pRect[i].x;
- DstRect.xRight = pRect[i].x + pRect[i].w;
- DstRect.yBottom = pRect[i].y + pRect[i].h;
- DstRect.yTop = pRect[i].y;
-
- if (SrcRect.xLeft < SrcViewPortRect.xLeft)
- {
- DstRect.xLeft += SrcViewPortRect.xLeft - SrcRect.xLeft;
- SrcRect.xLeft = SrcViewPortRect.xLeft;
- }
- else if (SrcRect.xLeft >= SrcViewPortRect.xRight)
- continue;
+ AssertFailed(); /* remove if annoying. */
+ ClippedRect.w = cxSurface - ClippedRect.srcx;
+ }
+
+ if (RT_LIKELY(ClippedRect.srcy < cySurface))
+ { /* likely */ }
+ else
+ continue;
+ if (RT_LIKELY(ClippedRect.srcy + ClippedRect.h <= cySurface))
+ { /* likely */ }
+ else
+ {
+ AssertFailed(); /* remove if annoying. */
+ ClippedRect.h = cySurface - ClippedRect.srcy;
+ }
- if (SrcRect.xRight > SrcViewPortRect.xRight)
+ /*
+ * Destination viewport clipping - real PITA.
+ *
+ * We have to take the following into account here:
+ * - The source image is Y inverted.
+ * - The destination framebuffer is in world and not window coordinates,
+ * just like the source surface. This means working in the first quadrant.
+ * - The viewport is in window coordinate, that is fourth quadrant and
+ * negated Y values.
+ * - The destination framebuffer is not scrolled, so we have to blit
+ * what's visible into the top of the framebuffer.
+ *
+ *
+ * To illustrate:
+ *
+ * source destination 0123456789
+ * 8 ^---------- 8 ^---------- 0 ----------->
+ * 7 | | 7 | | 1 | |
+ * 6 | | 6 | ******* | 2 | ******* |
+ * 5 | *** | 5 | * | 3 | * |
+ * 4 | * | => 4 | * | => 4 | * |
+ * 3 | * | 3 | *** | 5 | *** |
+ * 2 | ******* | 2 | | 6 | |
+ * 1 | | 1 | | 7 | |
+ * 0 -----------> 0 -----------> 8 v----------
+ * 0123456789 0123456789 Destination window
+ *
+ * From the above, it follows that a destination viewport given in
+ * window coordinates matches the source exactly when srcy = srcx = 0.
+ *
+ * Example (Y only):
+ * ySrc = 0
+ * yDst = 0
+ * cyCopy = 9
+ * cyScreen = cyCopy
+ * cySurface >= cyCopy
+ * yViewport = 5
+ * cyViewport = 2 (i.e. '| *** |'
+ * '| |' )
+ * yWCViewportHi = cxScreen - yViewport = 9 - 5 = 4
+ * yWCViewportLow = cxScreen - yViewport - cyViewport = 4 - 2 = 2
+ *
+ * We can see from the illustration that the final result should be:
+ * SrcRect = (0,7) (11, 5) (cy=2 from y=5)
+ * DstRect = (0,2) (11, 4)
+ *
+ * Let's postpone the switching of SrcRect.yBottom/yTop to make it
+ * easier to follow:
+ * SrcRect = (0,5) (11, 7)
+ *
+ * From the top, Y values only:
+ * 0. Copy = { .yDst = 0, .ySrc = 0, .cy = 9 }
+ *
+ * 1. CopyRect.yDst (=0) is lower than yWCViewportLow:
+ * cyAdjust = yWCViewportLow - CopyRect.yDst = 2;
+ * Copy.yDst += cyAdjust = 2;
+ * Copy.ySrc = unchanged;
+ * Copy.cx -= cyAdjust = 7;
+ * => Copy = { .yDst = 2, .ySrc = 0, .cy = 7 }
+ *
+ * 2. CopyRect.yDst + CopyRect.cx (=9) is higher than yWCViewportHi:
+ * cyAdjust = CopyRect.yDst + CopyRect.cx - yWCViewportHi = 9 - 4 = 5
+ * Copy.yDst = unchanged;
+ * Copy.ySrc += cyAdjust = 5;
+ * Copy.cx -= cyAdjust = 2;
+ * => Copy = { .yDst = 2, .ySrc = 5, .cy = 2 }
+ *
+ * Update: On darwin, it turns out that when we call [NSOpenGLContext updates]
+ * when the view is resized, moved and otherwise messed with,
+ * the visible part of the framebuffer is actually the bottom
+ * one. It's easy to adjust for this, just have to adjust the
+ * destination rectangle such that yBottom is zero.
+ */
+ /* X - no inversion, so kind of simple. */
+ if (ClippedRect.x >= DstViewport.x)
+ {
+ if (ClippedRect.x + ClippedRect.w <= DstViewport.xRight)
+ { /* typical */ }
+ else if (ClippedRect.x < DstViewport.xRight)
+ ClippedRect.w = DstViewport.xRight - ClippedRect.x;
+ else
+ continue;
+ }
+ else
+ {
+ uint32_t cxAdjust = DstViewport.x - ClippedRect.x;
+ if (cxAdjust < ClippedRect.w)
{
- DstRect.xRight -= SrcViewPortRect.xRight - SrcRect.xRight;
- SrcRect.xRight = SrcViewPortRect.xRight;
+ ClippedRect.w -= cxAdjust;
+ ClippedRect.x += cxAdjust;
+ ClippedRect.srcx += cxAdjust;
}
- else if (SrcRect.xRight <= SrcViewPortRect.xLeft)
+ else
continue;
- if (SrcRect.xRight <= SrcRect.xLeft)
- continue;
+ if (ClippedRect.x + ClippedRect.w <= DstViewport.xRight)
+ { /* typical */ }
+ else
+ ClippedRect.w = DstViewport.xRight - ClippedRect.x;
+ }
- if (SrcRect.yBottom < SrcViewPortRect.yBottom)
+ /* Y - complicated, see above. */
+ if (ClippedRect.y >= DstViewport.yLowWC)
+ {
+ if (ClippedRect.y + ClippedRect.h <= DstViewport.yHighWC)
+ { /* typical */ }
+ else if (ClippedRect.y < DstViewport.yHighWC)
{
- DstRect.yTop += SrcViewPortRect.yBottom - SrcRect.yBottom;
- SrcRect.yBottom = SrcViewPortRect.yBottom;
+ /* adjustment #2 */
+ uint32_t cyAdjust = ClippedRect.y + ClippedRect.h - DstViewport.yHighWC;
+ ClippedRect.srcy += cyAdjust;
+ ClippedRect.h -= cyAdjust;
}
- else if (SrcRect.yBottom >= SrcViewPortRect.yTop)
+ else
continue;
-
- if (SrcRect.yTop > SrcViewPortRect.yTop)
+ }
+ else
+ {
+ /* adjustment #1 */
+ uint32_t cyAdjust = DstViewport.yLowWC - ClippedRect.y;
+ if (cyAdjust < ClippedRect.h)
{
- DstRect.yBottom -= SrcViewPortRect.yTop - SrcRect.yTop;
- SrcRect.yTop = SrcViewPortRect.yTop;
+ ClippedRect.y += cyAdjust;
+ ClippedRect.h -= cyAdjust;
}
- else if (SrcRect.yTop <= SrcViewPortRect.yBottom)
- continue;
-
- if (SrcRect.yTop <= SrcRect.yBottom)
+ else
continue;
- Log(("SrcRect: (%d,%d)(%d,%d) DstRect: (%d,%d)(%d,%d)\n",
- SrcRect.xLeft, SrcRect.yBottom, SrcRect.xRight, SrcRect.yTop,
- DstRect.xLeft, DstRect.yBottom, DstRect.xRight, DstRect.yTop));
- pState->ext.glBlitFramebuffer(SrcRect.xLeft, SrcRect.yBottom, SrcRect.xRight, SrcRect.yTop,
- DstRect.xLeft, DstRect.yBottom, DstRect.xRight, DstRect.yTop,
- GL_COLOR_BUFFER_BIT, GL_LINEAR);
-
-# else
- if ( pRect[i].x + pRect[i].w <= pThis->svga.viewport.x
- || pThis->svga.viewport.x + pThis->svga.viewport.cx <= pRect[i].x
- || pRect[i].y + pRect[i].h <= pThis->svga.viewport.y
- || pThis->svga.viewport.y + pThis->svga.viewport.cy <= pRect[i].y)
+ if (ClippedRect.y + ClippedRect.h <= DstViewport.yHighWC)
+ { /* typical */ }
+ else
{
- /* Intersection is empty; skip */
- continue;
+ /* adjustment #2 */
+ cyAdjust = ClippedRect.y + ClippedRect.h - DstViewport.yHighWC;
+ ClippedRect.srcy += cyAdjust;
+ ClippedRect.h -= cyAdjust;
}
- pState->ext.glBlitFramebuffer(RT_MAX(pRect[i].srcx, srcViewPort.x),
- pSurface->pMipmapLevels[0].size.width - RT_MAX(pRect[i].srcy, srcViewPort.y), /* exclusive. (reverse to flip the image) */
- RT_MIN(pRect[i].srcx + pRect[i].w, srcViewPort.x + srcViewPort.cx), /* exclusive. */
- pSurface->pMipmapLevels[0].size.width - RT_MIN(pRect[i].srcy + pRect[i].h, srcViewPort.y + srcViewPort.cy),
- RT_MAX(pRect[i].x, pThis->svga.viewport.x) - pThis->svga.viewport.x,
- pThis->svga.uHeight - (RT_MIN(pRect[i].y + pRect[i].h, pThis->svga.viewport.y + pThis->svga.viewport.cy) - pThis->svga.viewport.y), /* exclusive. */
- RT_MIN(pRect[i].x + pRect[i].w, pThis->svga.viewport.x + pThis->svga.viewport.cx) - pThis->svga.viewport.x, /* exclusive. */
- pThis->svga.uHeight - (RT_MAX(pRect[i].y, pThis->svga.viewport.y) - pThis->svga.viewport.y),
- GL_COLOR_BUFFER_BIT,
- GL_LINEAR);
-# endif
}
+
+ /* Calc source rectangle with y flipping wrt destination. */
+ RTRECT SrcRect;
+ SrcRect.xLeft = ClippedRect.srcx;
+ SrcRect.xRight = ClippedRect.srcx + ClippedRect.w;
+ SrcRect.yBottom = ClippedRect.srcy + ClippedRect.h;
+ SrcRect.yTop = ClippedRect.srcy;
+
+ /* Calc destination rectangle. */
+ RTRECT DstRect;
+ DstRect.xLeft = ClippedRect.x;
+ DstRect.xRight = ClippedRect.x + ClippedRect.w;
+ DstRect.yBottom = ClippedRect.y;
+ DstRect.yTop = ClippedRect.y + ClippedRect.h;
+
+ /* Adjust for viewport. */
+ DstRect.xLeft -= DstViewport.x;
+ DstRect.xRight -= DstViewport.x;
+# ifdef RT_OS_DARWIN /* We actually seeing the bottom of the FB, not the top as on windows and X11. */
+ DstRect.yTop -= DstRect.yBottom;
+ DstRect.yBottom = 0;
+# else
+ DstRect.yBottom += DstViewport.y;
+ DstRect.yTop += DstViewport.y;
+# endif
+
+ Log(("SrcRect: (%d,%d)(%d,%d) DstRect: (%d,%d)(%d,%d)\n",
+ SrcRect.xLeft, SrcRect.yBottom, SrcRect.xRight, SrcRect.yTop,
+ DstRect.xLeft, DstRect.yBottom, DstRect.xRight, DstRect.yTop));
+ pState->ext.glBlitFramebuffer(SrcRect.xLeft, SrcRect.yBottom, SrcRect.xRight, SrcRect.yTop,
+ DstRect.xLeft, DstRect.yBottom, DstRect.xRight, DstRect.yTop,
+ GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
#endif
-#ifndef RT_OS_DARWIN /* darwin: later */
- /* Reset the frame buffer association - see below. */
- VMSVGA3D_ASSERT_GL_CALL(pState->ext.glBindFramebuffer(GL_FRAMEBUFFER, pContext->idFramebuffer), pState, pContext);
-#endif
/*
* Flip the front and back buffers.
@@ -4228,13 +3139,11 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
glXSwapBuffers(pState->display, pContext->window);
#endif
-#if defined(RT_OS_DARWIN)
/*
* Now we can reset the frame buffer association. Doing it earlier means no
* output on darwin.
*/
VMSVGA3D_ASSERT_GL_CALL(pState->ext.glBindFramebuffer(GL_FRAMEBUFFER, pContext->idFramebuffer), pState, pContext);
-#endif
return VINF_SUCCESS;
}
@@ -4277,19 +3186,15 @@ DECLCALLBACK(int) vmsvga3dXEventThread(RTTHREAD ThreadSelf, void *pvUser)
* @param cid Context id
* @param fFlags VMSVGA3D_DEF_CTX_F_XXX.
*/
-static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFlags)
+int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFlags)
{
int rc;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
AssertReturn( cid < SVGA3D_MAX_CONTEXT_IDS
|| (cid == VMSVGA3D_SHARED_CTX_ID && (fFlags & VMSVGA3D_DEF_CTX_F_SHARED_CTX)), VERR_INVALID_PARAMETER);
-#else
- AssertReturn(cid < SVGA3D_MAX_CONTEXT_IDS, VERR_INVALID_PARAMETER);
-#endif
#if !defined(VBOX_VMSVGA3D_DUAL_OPENGL_PROFILE) || !(defined(RT_OS_DARWIN))
AssertReturn(!(fFlags & VMSVGA3D_DEF_CTX_F_OTHER_PROFILE), VERR_INTERNAL_ERROR_3);
#endif
@@ -4304,11 +3209,9 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
}
#endif
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
if (cid == VMSVGA3D_SHARED_CTX_ID)
pContext = &pState->SharedCtx;
else
-#endif
{
if (cid >= pState->cContexts)
{
@@ -4333,9 +3236,8 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
}
/*
- * Find the shared context (necessary for sharing e.g. textures between contexts).
+ * Find or create the shared context if needed (necessary for sharing e.g. textures between contexts).
*/
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
PVMSVGA3DCONTEXT pSharedCtx = NULL;
if (!(fFlags & (VMSVGA3D_DEF_CTX_F_INIT | VMSVGA3D_DEF_CTX_F_SHARED_CTX)))
{
@@ -4346,23 +3248,6 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
AssertLogRelRCReturn(rc, rc);
}
}
-#else
- // TODO isn't this default on Linux since OpenGL 1.1?
- /* Find the first active context to share the display list with (necessary for sharing e.g. textures between contexts). */
- PVMSVGA3DCONTEXT pSharedCtx = NULL;
- for (uint32_t i = 0; i < pState->cContexts; i++)
- if ( pState->papContexts[i]->id != SVGA3D_INVALID_ID
- && i != cid
-# ifdef VBOX_VMSVGA3D_DUAL_OPENGL_PROFILE
- && pState->papContexts[i]->fOtherProfile == RT_BOOL(fFlags & VMSVGA3D_DEF_CTX_F_OTHER_PROFILE)
-# endif
- )
- {
- Log(("Sharing display lists between cid=%d and cid=%d\n", pContext->id, i));
- pSharedCtx = pState->papContexts[i];
- break;
- }
-#endif
/*
* Initialize the context.
@@ -4442,7 +3327,7 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
BOOL ret;
pixelFormat = ChoosePixelFormat(pContext->hdc, &pfd);
- /* @todo is this really necessary?? */
+ /** @todo is this really necessary?? */
pixelFormat = ChoosePixelFormat(pContext->hdc, &pfd);
AssertMsgReturn(pixelFormat != 0, ("ChoosePixelFormat failed with %d\n", GetLastError()), VERR_INTERNAL_ERROR);
@@ -4464,7 +3349,8 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
NativeNSOpenGLContextRef pShareContext = pSharedCtx ? pSharedCtx->cocoaContext : NULL;
NativeNSViewRef pHostView = (NativeNSViewRef)pThis->svga.u64HostWindowId;
vmsvga3dCocoaCreateViewAndContext(&pContext->cocoaView, &pContext->cocoaContext,
- pHostView, pThis->svga.uWidth, pThis->svga.uHeight,
+ pSharedCtx ? NULL : pHostView, /* Only attach one subview, the one we'll present in. */ /** @todo screen objects and stuff. */
+ pThis->svga.uWidth, pThis->svga.uHeight,
pShareContext, pContext->fOtherProfile);
#else
@@ -4539,7 +3425,7 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
}
#if 0
- /* @todo move to shader lib!!! */
+ /** @todo move to shader lib!!! */
/* Clear the screen */
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
@@ -4552,7 +3438,7 @@ static int vmsvga3dContextDefineOgl(PVGASTATE pThis, uint32_t cid, uint32_t fFla
glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
if (pState->ext.glProvokingVertex)
pState->ext.glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
- /* @todo move to shader lib!!! */
+ /** @todo move to shader lib!!! */
#endif
return VINF_SUCCESS;
}
@@ -4570,182 +3456,165 @@ int vmsvga3dContextDefine(PVGASTATE pThis, uint32_t cid)
return vmsvga3dContextDefineOgl(pThis, cid, 0/*fFlags*/);
}
-
/**
- * Destroy an existing 3d context
+ * Destroys a 3d context.
*
* @returns VBox status code.
* @param pThis VGA device instance data.
+ * @param pContext The context to destroy.
* @param cid Context id
*/
-int vmsvga3dContextDestroy(PVGASTATE pThis, uint32_t cid)
+static int vmsvga3dContextDestroyOgl(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t cid)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
+ AssertReturn(pContext, VERR_INVALID_PARAMETER);
+ AssertReturn(pContext->id == cid, VERR_INVALID_PARAMETER);
+ Log(("vmsvga3dContextDestroyOgl id %x\n", cid));
- AssertReturn(cid < SVGA3D_MAX_CONTEXT_IDS, VERR_INVALID_PARAMETER);
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
- if ( cid < pState->cContexts
- && pState->papContexts[cid]->id == cid)
+ /* Destroy all leftover pixel shaders. */
+ for (uint32_t i = 0; i < pContext->cPixelShaders; i++)
{
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
-
- Log(("vmsvga3dContextDestroy id %x\n", cid));
+ if (pContext->paPixelShader[i].id != SVGA3D_INVALID_ID)
+ vmsvga3dShaderDestroy(pThis, pContext->paPixelShader[i].cid, pContext->paPixelShader[i].id, pContext->paPixelShader[i].type);
+ }
+ if (pContext->paPixelShader)
+ RTMemFree(pContext->paPixelShader);
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
+ /* Destroy all leftover vertex shaders. */
+ for (uint32_t i = 0; i < pContext->cVertexShaders; i++)
+ {
+ if (pContext->paVertexShader[i].id != SVGA3D_INVALID_ID)
+ vmsvga3dShaderDestroy(pThis, pContext->paVertexShader[i].cid, pContext->paVertexShader[i].id, pContext->paVertexShader[i].type);
+ }
+ if (pContext->paVertexShader)
+ RTMemFree(pContext->paVertexShader);
- /* Destroy all leftover pixel shaders. */
- for (uint32_t i = 0; i < pContext->cPixelShaders; i++)
- {
- if (pContext->paPixelShader[i].id != SVGA3D_INVALID_ID)
- vmsvga3dShaderDestroy(pThis, pContext->paPixelShader[i].cid, pContext->paPixelShader[i].id, pContext->paPixelShader[i].type);
- }
- if (pContext->paPixelShader)
- RTMemFree(pContext->paPixelShader);
+ if (pContext->state.paVertexShaderConst)
+ RTMemFree(pContext->state.paVertexShaderConst);
+ if (pContext->state.paPixelShaderConst)
+ RTMemFree(pContext->state.paPixelShaderConst);
- /* Destroy all leftover vertex shaders. */
- for (uint32_t i = 0; i < pContext->cVertexShaders; i++)
- {
- if (pContext->paVertexShader[i].id != SVGA3D_INVALID_ID)
- vmsvga3dShaderDestroy(pThis, pContext->paVertexShader[i].cid, pContext->paVertexShader[i].id, pContext->paVertexShader[i].type);
- }
- if (pContext->paVertexShader)
- RTMemFree(pContext->paVertexShader);
+ if (pContext->pShaderContext)
+ {
+ int rc = ShaderContextDestroy(pContext->pShaderContext);
+ AssertRC(rc);
+ }
- if (pContext->state.paVertexShaderConst)
- RTMemFree(pContext->state.paVertexShaderConst);
- if (pContext->state.paPixelShaderConst)
- RTMemFree(pContext->state.paPixelShaderConst);
+ if (pContext->idFramebuffer != OPENGL_INVALID_ID)
+ {
+ /* Unbind the object from the framebuffer target. */
+ pState->ext.glBindFramebuffer(GL_FRAMEBUFFER, 0 /* back buffer */);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ pState->ext.glDeleteFramebuffers(1, &pContext->idFramebuffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- if (pContext->pShaderContext)
+ if (pContext->idReadFramebuffer != OPENGL_INVALID_ID)
{
- int rc = ShaderContextDestroy(pContext->pShaderContext);
- AssertRC(rc);
+ pState->ext.glDeleteFramebuffers(1, &pContext->idReadFramebuffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
}
-
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX /* This is done on windows - prevents various assertions at runtime, as well as shutdown & reset assertions when destroying surfaces. */
- /* Check for all surfaces that are associated with this context to remove all dependencies */
- for (uint32_t sid = 0; sid < pState->cSurfaces; sid++)
+ if (pContext->idDrawFramebuffer != OPENGL_INVALID_ID)
{
- PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
- if ( pSurface->idAssociatedContext == cid
- && pSurface->id == sid)
- {
- int rc;
-
- Log(("vmsvga3dContextDestroy: remove all dependencies for surface %x\n", sid));
+ pState->ext.glDeleteFramebuffers(1, &pContext->idDrawFramebuffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ }
+ }
+#ifdef RT_OS_WINDOWS
+ wglMakeCurrent(pContext->hdc, NULL);
+ wglDeleteContext(pContext->hglrc);
+ ReleaseDC(pContext->hwnd, pContext->hdc);
- uint32_t surfaceFlags = pSurface->flags;
- SVGA3dSurfaceFormat format = pSurface->format;
- SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES];
- uint32_t multisampleCount = pSurface->multiSampleCount;
- SVGA3dTextureFilter autogenFilter = pSurface->autogenFilter;
- SVGA3dSize *pMipLevelSize;
- uint32_t cFaces = pSurface->cFaces;
+ /* Destroy the window we've created. */
+ int rc = vmsvga3dSendThreadMessage(pState->pWindowThread, pState->WndRequestSem, WM_VMSVGA3D_DESTROYWINDOW, (WPARAM)pContext->hwnd, 0);
+ AssertRC(rc);
+#elif defined(RT_OS_DARWIN)
+ vmsvga3dCocoaDestroyViewAndContext(pContext->cocoaView, pContext->cocoaContext);
+#elif defined(RT_OS_LINUX)
+ glXMakeCurrent(pState->display, None, NULL);
+ glXDestroyContext(pState->display, pContext->glxContext);
+ XDestroyWindow(pState->display, pContext->window);
+#endif
- pMipLevelSize = (SVGA3dSize *)RTMemAllocZ(pSurface->faces[0].numMipLevels * pSurface->cFaces * sizeof(SVGA3dSize));
- AssertReturn(pMipLevelSize, VERR_NO_MEMORY);
+ memset(pContext, 0, sizeof(*pContext));
+ pContext->id = SVGA3D_INVALID_ID;
- for (uint32_t iFace = 0; iFace < pSurface->cFaces; iFace++)
- {
- for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
- {
- uint32_t idx = i + iFace * pSurface->faces[0].numMipLevels;
- memcpy(&pMipLevelSize[idx], &pSurface->pMipmapLevels[idx].size, sizeof(SVGA3dSize));
- }
- }
- memcpy(face, pSurface->faces, sizeof(pSurface->faces));
+ VMSVGA3D_CLEAR_CURRENT_CONTEXT(pState);
+ return VINF_SUCCESS;
+}
- /* Recreate the surface with the original settings; destroys the contents, but that seems fairly safe since the context is also destroyed. */
- rc = vmsvga3dSurfaceDestroy(pThis, sid);
- AssertRC(rc);
+/**
+ * Destroy an existing 3d context
+ *
+ * @returns VBox status code.
+ * @param pThis VGA device instance data.
+ * @param cid Context id
+ */
+int vmsvga3dContextDestroy(PVGASTATE pThis, uint32_t cid)
+{
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturn(pState, VERR_WRONG_ORDER);
- rc = vmsvga3dSurfaceDefine(pThis, sid, surfaceFlags, format, face, multisampleCount, autogenFilter, face[0].numMipLevels * cFaces, pMipLevelSize);
- AssertRC(rc);
- }
- }
-#endif
+ /*
+ * Resolve the context and hand it to the common worker function.
+ */
+ if ( cid < pState->cContexts
+ && pState->papContexts[cid]->id == cid)
+ return vmsvga3dContextDestroyOgl(pThis, pState->papContexts[cid], cid);
- if (pContext->idFramebuffer != OPENGL_INVALID_ID)
- {
- /* Unbind the object from the framebuffer target. */
- pState->ext.glBindFramebuffer(GL_FRAMEBUFFER, 0 /* back buffer */);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- pState->ext.glDeleteFramebuffers(1, &pContext->idFramebuffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
+ AssertReturn(cid < SVGA3D_MAX_CONTEXT_IDS, VERR_INVALID_PARAMETER);
+ return VINF_SUCCESS;
+}
- if (pContext->idReadFramebuffer != OPENGL_INVALID_ID)
- {
- pState->ext.glDeleteFramebuffers(1, &pContext->idReadFramebuffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- if (pContext->idDrawFramebuffer != OPENGL_INVALID_ID)
- {
- pState->ext.glDeleteFramebuffers(1, &pContext->idDrawFramebuffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
- }
+/**
+ * Worker for vmsvga3dChangeMode that resizes a context.
+ *
+ * @param pThis The VGA device instance data.
+ * @param pState The VMSVGA3d state.
+ * @param pContext The context.
+ */
+static void vmsvga3dChangeModeOneContext(PVGASTATE pThis, PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext)
+{
#ifdef RT_OS_WINDOWS
- wglMakeCurrent(pContext->hdc, NULL);
- wglDeleteContext(pContext->hglrc);
- ReleaseDC(pContext->hwnd, pContext->hdc);
+ /* Resize the window. */
+ CREATESTRUCT cs;
+ RT_ZERO(cs);
+ cs.cx = pThis->svga.uWidth;
+ cs.cy = pThis->svga.uHeight;
+ int rc = vmsvga3dSendThreadMessage(pState->pWindowThread, pState->WndRequestSem, WM_VMSVGA3D_RESIZEWINDOW, (WPARAM)pContext->hwnd, (LPARAM)&cs);
+ AssertRC(rc);
- /* Destroy the window we've created. */
- int rc = vmsvga3dSendThreadMessage(pState->pWindowThread, pState->WndRequestSem, WM_VMSVGA3D_DESTROYWINDOW, (WPARAM)pContext->hwnd, 0);
- AssertRC(rc);
#elif defined(RT_OS_DARWIN)
- vmsvga3dCocoaDestroyViewAndContext(pContext->cocoaView, pContext->cocoaContext);
+ vmsvga3dCocoaViewSetSize(pContext->cocoaView, pThis->svga.uWidth, pThis->svga.uHeight);
+
#elif defined(RT_OS_LINUX)
- glXMakeCurrent(pState->display, None, NULL);
- glXDestroyContext(pState->display, pContext->glxContext);
- XDestroyWindow(pState->display, pContext->window);
+ XWindowChanges wc;
+ wc.width = pThis->svga.uWidth;
+ wc.height = pThis->svga.uHeight;
+ XConfigureWindow(pState->display, pContext->window, CWWidth | CWHeight, &wc);
#endif
-
- memset(pContext, 0, sizeof(*pContext));
- pContext->id = SVGA3D_INVALID_ID;
-
- VMSVGA3D_CLEAR_CURRENT_CONTEXT(pState);
- }
- else
- AssertFailed();
-
- return VINF_SUCCESS;
}
/* Handle resize */
int vmsvga3dChangeMode(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
+ /* Resize the shared context too. */
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ vmsvga3dChangeModeOneContext(pThis, pState, &pState->SharedCtx);
+
/* Resize all active contexts. */
for (uint32_t i = 0; i < pState->cContexts; i++)
{
PVMSVGA3DCONTEXT pContext = pState->papContexts[i];
- uint32_t cid = pContext->id;
-
- if (cid != SVGA3D_INVALID_ID)
- {
-#ifdef RT_OS_WINDOWS
- CREATESTRUCT cs;
-
- memset(&cs, 0, sizeof(cs));
- cs.cx = pThis->svga.uWidth;
- cs.cy = pThis->svga.uHeight;
-
- /* Resize the window. */
- int rc = vmsvga3dSendThreadMessage(pState->pWindowThread, pState->WndRequestSem, WM_VMSVGA3D_RESIZEWINDOW, (WPARAM)pContext->hwnd, (LPARAM)&cs);
- AssertRC(rc);
-#elif defined(RT_OS_DARWIN)
- vmsvga3dCocoaViewSetSize(pContext->cocoaView, pThis->svga.uWidth, pThis->svga.uHeight);
-#elif defined(RT_OS_LINUX)
- XWindowChanges wc;
- wc.width = pThis->svga.uWidth;
- wc.height = pThis->svga.uHeight;
- XConfigureWindow(pState->display, pContext->window, CWWidth | CWHeight, &wc);
-#endif
- }
+ if (pContext->id != SVGA3D_INVALID_ID)
+ vmsvga3dChangeModeOneContext(pThis, pState, pContext);
}
+
return VINF_SUCCESS;
}
@@ -4753,7 +3622,7 @@ int vmsvga3dChangeMode(PVGASTATE pThis)
int vmsvga3dSetTransform(PVGASTATE pThis, uint32_t cid, SVGA3dTransformType type, float matrix[16])
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
bool fModelViewChanged = false;
@@ -4861,7 +3730,7 @@ int vmsvga3dSetTransform(PVGASTATE pThis, uint32_t cid, SVGA3dTransformType type
int vmsvga3dSetZRange(PVGASTATE pThis, uint32_t cid, SVGA3dZRange zRange)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetZRange cid=%x min=%d max=%d\n", cid, (uint32_t)(zRange.min * 100.0), (uint32_t)(zRange.max * 100.0)));
@@ -4918,9 +3787,9 @@ static GLenum vmsvga3dBlendOp2GL(uint32_t blendOp)
case SVGA3D_BLENDOP_SRCALPHASAT:
return GL_SRC_ALPHA_SATURATE;
case SVGA3D_BLENDOP_BLENDFACTOR:
- return GL_CONSTANT_ALPHA; /* @todo correct?? */
+ return GL_CONSTANT_ALPHA; /** @todo correct?? */
case SVGA3D_BLENDOP_INVBLENDFACTOR:
- return GL_ONE_MINUS_CONSTANT_ALPHA; /* @todo correct?? */
+ return GL_ONE_MINUS_CONSTANT_ALPHA; /** @todo correct?? */
default:
AssertFailed();
return GL_ONE;
@@ -4942,7 +3811,7 @@ static GLenum vmsvga3dBlendEquation2GL(uint32_t blendEq)
case SVGA3D_BLENDEQ_MAXIMUM:
return GL_MAX;
default:
- AssertFailed();
+ AssertMsgFailed(("blendEq=%d (%#x)\n", blendEq, blendEq));
return GL_FUNC_ADD;
}
}
@@ -5003,7 +3872,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
{
uint32_t val;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetRenderState cid=%x cRenderStates=%d\n", cid, cRenderStates));
@@ -5072,7 +3941,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
break;
case SVGA3D_RS_POINTSIZE: /* float */
- /* @todo we need to apply scaling for point sizes below the min or above the max; see Wine) */
+ /** @todo we need to apply scaling for point sizes below the min or above the max; see Wine) */
if (pRenderState[i].floatValue < pState->caps.flPointSize[0])
pRenderState[i].floatValue = pState->caps.flPointSize[0];
if (pRenderState[i].floatValue > pState->caps.flPointSize[1])
@@ -5180,7 +4049,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
break;
}
- /* @todo how to switch between vertex and pixel fog modes??? */
+ /** @todo how to switch between vertex and pixel fog modes??? */
Assert(mode.s.type == SVGA3D_FOGTYPE_PIXEL);
#if 0
/* The fog type determines the render state. */
@@ -5267,7 +4136,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
case SVGA3D_RS_LINEPATTERN: /* SVGA3dLinePattern */
/* No longer supported by d3d; mesagl comments suggest not all backends support it */
- /* @todo */
+ /** @todo */
Log(("WARNING: SVGA3D_RS_LINEPATTERN %x not supported!!\n", pRenderState[i].uintValue));
/*
renderState = D3DRS_LINEPATTERN;
@@ -5541,8 +4410,8 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
case SVGA3D_RS_CCWSTENCILFUNC: /* SVGA3dCmpFunc */
{
- /* @todo SVGA3D_RS_STENCILFAIL/ZFAIL/PASS for front & back faces
- * SVGA3D_RS_CCWSTENCILFAIL/ZFAIL/PASS for back faces ??
+ /** @todo SVGA3D_RS_STENCILFAIL/ZFAIL/PASS for front & back faces
+ * SVGA3D_RS_CCWSTENCILFAIL/ZFAIL/PASS for back faces ??
*/
GLint ref;
GLuint mask;
@@ -5561,8 +4430,8 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
case SVGA3D_RS_CCWSTENCILZFAIL: /* SVGA3dStencilOp */
case SVGA3D_RS_CCWSTENCILPASS: /* SVGA3dStencilOp */
{
- /* @todo SVGA3D_RS_STENCILFAIL/ZFAIL/PASS for front & back faces
- * SVGA3D_RS_CCWSTENCILFAIL/ZFAIL/PASS for back faces ??
+ /** @todo SVGA3D_RS_STENCILFAIL/ZFAIL/PASS for front & back faces
+ * SVGA3D_RS_CCWSTENCILFAIL/ZFAIL/PASS for back faces ??
*/
GLint sfail, dpfail, dppass;
GLenum stencilop = vmsvgaStencipOp2GL(pRenderState[i].uintValue);
@@ -5596,7 +4465,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
}
case SVGA3D_RS_ZBIAS: /* float */
- /* @todo unknown meaning; depth bias is not identical
+ /** @todo unknown meaning; depth bias is not identical
renderState = D3DRS_DEPTHBIAS;
val = pRenderState[i].uintValue;
*/
@@ -5607,7 +4476,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
{
GLfloat factor;
- /* @todo not sure if the d3d & ogl definitions are identical. */
+ /** @todo not sure if the d3d & ogl definitions are identical. */
/* Do not change the factor part. */
glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &factor);
@@ -5622,7 +4491,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
{
GLfloat units;
- /* @todo not sure if the d3d & ogl definitions are identical. */
+ /** @todo not sure if the d3d & ogl definitions are identical. */
/* Do not change the factor part. */
glGetFloatv(GL_POLYGON_OFFSET_UNITS, &units);
@@ -5719,7 +4588,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
case SVGA3D_RS_COORDINATETYPE: /* SVGA3dCoordinateType */
Assert(pRenderState[i].uintValue == SVGA3D_COORDINATE_LEFTHANDED);
- /* @todo setup a view matrix to scale the world space by -1 in the z-direction for right handed coordinates. */
+ /** @todo setup a view matrix to scale the world space by -1 in the z-direction for right handed coordinates. */
/*
renderState = D3DRS_COORDINATETYPE;
val = pRenderState[i].uintValue;
@@ -5833,7 +4702,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetType type, SVGA3dSurfaceImageId target)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pRenderTarget;
AssertReturn(pState, VERR_NO_MEMORY);
@@ -5896,10 +4765,9 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
if (pRenderTarget->oglId.texture == OPENGL_INVALID_ID)
{
Log(("vmsvga3dSetRenderTarget: create renderbuffer to be used as render target; surface id=%x type=%d format=%d\n", target.sid, pRenderTarget->flags, pRenderTarget->internalFormatGL));
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
+
pState->ext.glGenRenderbuffers(1, &pRenderTarget->oglId.renderbuffer);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -5912,30 +4780,16 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
pRenderTarget->pMipmapLevels[0].size.height);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
pState->ext.glBindRenderbuffer(GL_RENDERBUFFER, OPENGL_INVALID_ID);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
pContext = pState->papContexts[cid];
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-# ifdef VMSVGA3D_OGL_WITH_SHARED_CTX_EXPERIMENT_1
pRenderTarget->idWeakContextAssociation = cid;
-# endif
-#else
- LogFlow(("vmsvga3dSetRenderTarget: sid=%x idAssociatedContext %#x -> %#x\n", pRenderTarget->id, pRenderTarget->idAssociatedContext, cid));
- pRenderTarget->idAssociatedContext = cid;
-#endif
}
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- else
-#endif
- {
- pState->ext.glBindRenderbuffer(GL_RENDERBUFFER, pRenderTarget->oglId.renderbuffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- Assert(pRenderTarget->idAssociatedContext == cid);
-#endif
+
+ pState->ext.glBindRenderbuffer(GL_RENDERBUFFER, pRenderTarget->oglId.renderbuffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
Assert(!pRenderTarget->fDirty);
AssertReturn(pRenderTarget->oglId.texture != OPENGL_INVALID_ID, VERR_INVALID_PARAMETER);
@@ -5960,7 +4814,7 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
if (pRenderTarget->oglId.texture == OPENGL_INVALID_ID)
{
Log(("vmsvga3dSetRenderTarget: create texture to be used as render target; surface id=%x type=%d format=%d -> create texture\n", target.sid, pRenderTarget->flags, pRenderTarget->format));
- int rc = vmsvga3dCreateTexture(pState, pContext, cid, pRenderTarget);
+ int rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pRenderTarget);
AssertRCReturn(rc, rc);
}
@@ -5979,7 +4833,7 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
if (status != GL_FRAMEBUFFER_COMPLETE)
Log(("vmsvga3dSetRenderTarget: WARNING: glCheckFramebufferStatus returned %x\n", status));
#endif
- /* @todo use glDrawBuffers too? */
+ /** @todo use glDrawBuffers too? */
break;
}
@@ -6025,7 +4879,7 @@ static DWORD vmsvga3dTextureCombiner2D3D(uint32_t value)
case SVGA3D_TC_MODULATE4X:
return D3DTOP_MODULATE4X;
case SVGA3D_TC_DSDT:
- AssertFailed(); /* @todo ??? */
+ AssertFailed(); /** @todo ??? */
return D3DTOP_DISABLE;
case SVGA3D_TC_DOTPRODUCT3:
return D3DTOP_DOTPRODUCT3;
@@ -6090,13 +4944,13 @@ static DWORD vmsvga3dTextTransformFlags2D3D(uint32_t value)
case SVGA3D_TEX_TRANSFORM_OFF:
return D3DTTFF_DISABLE;
case SVGA3D_TEX_TRANSFORM_S:
- return D3DTTFF_COUNT1; /* @todo correct? */
+ return D3DTTFF_COUNT1; /** @todo correct? */
case SVGA3D_TEX_TRANSFORM_T:
- return D3DTTFF_COUNT2; /* @todo correct? */
+ return D3DTTFF_COUNT2; /** @todo correct? */
case SVGA3D_TEX_TRANSFORM_R:
- return D3DTTFF_COUNT3; /* @todo correct? */
+ return D3DTTFF_COUNT3; /** @todo correct? */
case SVGA3D_TEX_TRANSFORM_Q:
- return D3DTTFF_COUNT4; /* @todo correct? */
+ return D3DTTFF_COUNT4; /** @todo correct? */
case SVGA3D_TEX_PROJECTED:
return D3DTTFF_PROJECTED;
default:
@@ -6120,7 +4974,7 @@ static GLenum vmsvga3dTextureAddress2OGL(SVGA3dTextureAddress value)
return GL_CLAMP_TO_BORDER;
case SVGA3D_TEX_ADDRESS_MIRRORONCE:
AssertFailed();
- return GL_CLAMP_TO_EDGE_SGIS; /* @todo correct? */
+ return GL_CLAMP_TO_EDGE_SGIS; /** @todo correct? */
case SVGA3D_TEX_ADDRESS_EDGE:
case SVGA3D_TEX_ADDRESS_INVALID:
@@ -6140,7 +4994,7 @@ static GLenum vmsvga3dTextureFilter2OGL(SVGA3dTextureFilter value)
case SVGA3D_TEX_FILTER_NEAREST:
return GL_NEAREST;
case SVGA3D_TEX_FILTER_ANISOTROPIC:
- /* @todo */
+ /** @todo */
case SVGA3D_TEX_FILTER_FLATCUBIC: // Deprecated, not implemented
case SVGA3D_TEX_FILTER_GAUSSIANCUBIC: // Deprecated, not implemented
case SVGA3D_TEX_FILTER_PYRAMIDALQUAD: // Not currently implemented
@@ -6164,7 +5018,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
GLenum val;
GLenum currentStage = ~0L;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetTextureState %x cTextureState=%d\n", cid, cTextureStates));
@@ -6228,7 +5082,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
case SVGA3D_TS_ALPHAARG0: /* SVGA3dTextureArgData */
case SVGA3D_TS_ALPHAARG1: /* SVGA3dTextureArgData */
case SVGA3D_TS_ALPHAARG2: /* SVGA3dTextureArgData */
- /* @todo; not used by MesaGL */
+ /** @todo not used by MesaGL */
Log(("vmsvga3dSetTextureState: colorop/alphaop not yet supported!!\n"));
break;
#if 0
@@ -6273,11 +5127,8 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
if (pSurface->oglId.texture == OPENGL_INVALID_ID)
{
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- Assert(pSurface->idAssociatedContext == SVGA3D_INVALID_ID);
-#endif
Log(("CreateTexture (%d,%d) level=%d\n", pSurface->pMipmapLevels[0].size.width, pSurface->pMipmapLevels[0].size.height, pSurface->faces[0].numMipLevels));
- int rc = vmsvga3dCreateTexture(pState, pContext, cid, pSurface);
+ int rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pSurface);
AssertRCReturn(rc, rc);
}
@@ -6365,13 +5216,13 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
vmsvgaColor2GLFloatArray(pTextureState[i].value, &color[0], &color[1], &color[2], &color[3]);
- glTexParameterfv(GL_TEXTURE_2D /* @todo flexible type */, GL_TEXTURE_BORDER_COLOR, color); /* Identical; default 0.0 identical too */
+ glTexParameterfv(GL_TEXTURE_2D /** @todo flexible type */, GL_TEXTURE_BORDER_COLOR, color); /* Identical; default 0.0 identical too */
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
break;
}
case SVGA3D_TS_TEXTURE_LOD_BIAS: /* float */
- glTexParameterf(GL_TEXTURE_2D /* @todo flexible type */, GL_TEXTURE_LOD_BIAS, pTextureState[i].value); /* Identical; default 0.0 identical too */
+ glTexParameterf(GL_TEXTURE_2D /** @todo flexible type */, GL_TEXTURE_LOD_BIAS, pTextureState[i].value); /* Identical; default 0.0 identical too */
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
break;
@@ -6407,7 +5258,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
if (textureType != ~0U)
{
- glTexParameteri(GL_TEXTURE_2D /* @todo flexible type */, textureType, val);
+ glTexParameteri(GL_TEXTURE_2D /** @todo flexible type */, textureType, val);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
}
}
@@ -6418,7 +5269,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
int vmsvga3dSetMaterial(PVGASTATE pThis, uint32_t cid, SVGA3dFace face, SVGA3dMaterial *pMaterial)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
GLenum oglFace;
@@ -6467,11 +5318,11 @@ int vmsvga3dSetMaterial(PVGASTATE pThis, uint32_t cid, SVGA3dFace face, SVGA3dMa
return VINF_SUCCESS;
}
-/* @todo Move into separate library as we are using logic from Wine here. */
+/** @todo Move into separate library as we are using logic from Wine here. */
int vmsvga3dSetLightData(PVGASTATE pThis, uint32_t cid, uint32_t index, SVGA3dLightData *pData)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
float QuadAttenuation;
@@ -6544,7 +5395,7 @@ int vmsvga3dSetLightData(PVGASTATE pThis, uint32_t cid, uint32_t index, SVGA3dLi
glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, (QuadAttenuation < pData->attenuation2) ? pData->attenuation2 : QuadAttenuation);
VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* @todo range */
+ /** @todo range */
break;
}
@@ -6612,7 +5463,7 @@ int vmsvga3dSetLightData(PVGASTATE pThis, uint32_t cid, uint32_t index, SVGA3dLi
glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, (QuadAttenuation < pData->attenuation2) ? pData->attenuation2 : QuadAttenuation);
VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- /* @todo range */
+ /** @todo range */
break;
}
@@ -6651,7 +5502,7 @@ int vmsvga3dSetLightData(PVGASTATE pThis, uint32_t cid, uint32_t index, SVGA3dLi
int vmsvga3dSetLightEnabled(PVGASTATE pThis, uint32_t cid, uint32_t index, uint32_t enabled)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetLightEnabled cid=%x %d -> %d\n", cid, index, enabled));
@@ -6688,7 +5539,7 @@ int vmsvga3dSetLightEnabled(PVGASTATE pThis, uint32_t cid, uint32_t index, uint3
int vmsvga3dSetViewPort(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetViewPort cid=%x (%d,%d)(%d,%d)\n", cid, pRect->x, pRect->y, pRect->w, pRect->h));
@@ -6706,7 +5557,7 @@ int vmsvga3dSetViewPort(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
pContext->state.RectViewPort = *pRect;
pContext->state.u32UpdateFlags |= VMSVGA3D_UPDATE_VIEWPORT;
- /* @todo y-inversion for partial viewport coordinates? */
+ /** @todo y-inversion for partial viewport coordinates? */
glViewport(pRect->x, pRect->y, pRect->w, pRect->h);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -6734,7 +5585,7 @@ int vmsvga3dSetViewPort(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
int vmsvga3dSetClipPlane(PVGASTATE pThis, uint32_t cid, uint32_t index, float plane[4])
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
double oglPlane[4];
@@ -6769,7 +5620,7 @@ int vmsvga3dSetClipPlane(PVGASTATE pThis, uint32_t cid, uint32_t index, float p
int vmsvga3dSetScissorRect(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetScissorRect cid=%x (%d,%d)(%d,%d)\n", cid, pRect->x, pRect->y, pRect->w, pRect->h));
@@ -6807,7 +5658,7 @@ int vmsvga3dCommandClear(PVGASTATE pThis, uint32_t cid, SVGA3dClearFlag clearFla
{
GLbitfield mask = 0;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
GLboolean fDepthWriteEnabled = GL_FALSE;
@@ -6835,7 +5686,7 @@ int vmsvga3dCommandClear(PVGASTATE pThis, uint32_t cid, SVGA3dClearFlag clearFla
}
if (clearFlag & SVGA3D_CLEAR_STENCIL)
{
- /* @todo possibly the same problem as with glDepthMask */
+ /** @todo possibly the same problem as with glDepthMask */
glClearStencil(stencil);
mask |= GL_STENCIL_BUFFER_BIT;
}
@@ -6947,13 +5798,13 @@ int vmsvga3dVertexDecl2OGL(SVGA3dVertexArrayIdentity &identity, GLint &size, GLe
case SVGA3D_DECLTYPE_UDEC3:
size = 3;
- type = GL_UNSIGNED_INT_2_10_10_10_REV; /* @todo correct? */
+ type = GL_UNSIGNED_INT_2_10_10_10_REV; /** @todo correct? */
break;
case SVGA3D_DECLTYPE_DEC3N:
normalized = true;
size = 3;
- type = GL_INT_2_10_10_10_REV; /* @todo correct? */
+ type = GL_INT_2_10_10_10_REV; /** @todo correct? */
break;
case SVGA3D_DECLTYPE_FLOAT16_2:
@@ -7025,11 +5876,9 @@ int vmsvga3dDrawPrimitivesProcessVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
if (pVertexSurface->oglId.buffer == OPENGL_INVALID_ID)
{
Log(("vmsvga3dDrawPrimitives: create vertex buffer fDirty=%d size=%x bytes\n", pVertexSurface->fDirty, pVertexSurface->pMipmapLevels[0].cbSurface));
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
PVMSVGA3DCONTEXT pSavedCtx = pContext;
pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
pState->ext.glGenBuffers(1, &pVertexSurface->oglId.buffer);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -7038,7 +5887,7 @@ int vmsvga3dDrawPrimitivesProcessVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
Assert(pVertexSurface->fDirty);
- /* @todo rethink usage dynamic/static */
+ /** @todo rethink usage dynamic/static */
pState->ext.glBufferData(GL_ARRAY_BUFFER, pVertexSurface->pMipmapLevels[0].cbSurface, pVertexSurface->pMipmapLevels[0].pSurfaceData, GL_DYNAMIC_DRAW);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -7047,26 +5896,16 @@ int vmsvga3dDrawPrimitivesProcessVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
pVertexSurface->flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER;
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
pState->ext.glBindBuffer(GL_ARRAY_BUFFER, OPENGL_INVALID_ID);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
pContext = pSavedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
- }
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- else
-#endif
- {
- Assert(pVertexSurface->fDirty == false);
- pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pVertexSurface->oglId.buffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
}
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- pVertexSurface->idAssociatedContext = pContext->id;
- LogFlow(("vmsvga3dDrawPrimitivesProcessVertexDecls: sid=%x idAssociatedContext %#x -> %#x\n", pVertexSurface->id, pVertexSurface->idAssociatedContext, pContext->id));
-#endif
+
+ Assert(pVertexSurface->fDirty == false);
+ pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pVertexSurface->oglId.buffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
/* Setup the vertex declarations. */
for (unsigned iVertex = 0; iVertex < numVertexDecls; iVertex++)
@@ -7089,7 +5928,7 @@ int vmsvga3dDrawPrimitivesProcessVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
pState->ext.glVertexAttribPointer(index, size, type, normalized, pVertexDecl[iVertex].array.stride,
(const GLvoid *)(uintptr_t)pVertexDecl[iVertex].array.offset);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- /* case SVGA3D_DECLUSAGE_COLOR: @todo color component order not identical!! test GL_BGRA!! */
+ /** @todo case SVGA3D_DECLUSAGE_COLOR: color component order not identical!! test GL_BGRA!! */
}
else
{
@@ -7225,7 +6064,7 @@ int vmsvga3dDrawPrimitivesCleanupVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
break;
case SVGA3D_DECLUSAGE_POSITIONT:
break;
- case SVGA3D_DECLUSAGE_COLOR: /* @todo color component order not identical!! */
+ case SVGA3D_DECLUSAGE_COLOR: /** @todo color component order not identical!! */
glDisableClientState(GL_COLOR_ARRAY);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
break;
@@ -7250,7 +6089,7 @@ int vmsvga3dDrawPrimitivesCleanupVertexDecls(PVMSVGA3DSTATE pState, PVMSVGA3DCON
int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecls, SVGA3dVertexDecl *pVertexDecl, uint32_t numRanges, SVGA3dPrimitiveRange *pRange, uint32_t cVertexDivisor, SVGA3dVertexDivisor *pVertexDivisor)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_INTERNAL_ERROR);
int rc = VERR_NOT_IMPLEMENTED;
uint32_t iCurrentVertex;
@@ -7260,7 +6099,7 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
AssertReturn(numVertexDecls && numVertexDecls <= SVGA3D_MAX_VERTEX_ARRAYS, VERR_INVALID_PARAMETER);
AssertReturn(numRanges && numRanges <= SVGA3D_MAX_DRAW_PRIMITIVE_RANGES, VERR_INVALID_PARAMETER);
AssertReturn(!cVertexDivisor || cVertexDivisor == numVertexDecls, VERR_INVALID_PARAMETER);
- /* @todo */
+ /** @todo Non-zero cVertexDivisor */
Assert(!cVertexDivisor);
if ( cid >= pState->cContexts
@@ -7343,10 +6182,8 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
if (pIndexSurface->oglId.buffer == OPENGL_INVALID_ID)
{
Log(("vmsvga3dDrawPrimitives: create index buffer fDirty=%d size=%x bytes\n", pIndexSurface->fDirty, pIndexSurface->pMipmapLevels[0].cbSurface));
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
pState->ext.glGenBuffers(1, &pIndexSurface->oglId.buffer);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -7356,7 +6193,7 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
Assert(pIndexSurface->fDirty);
- /* @todo rethink usage dynamic/static */
+ /** @todo rethink usage dynamic/static */
pState->ext.glBufferData(GL_ELEMENT_ARRAY_BUFFER, pIndexSurface->pMipmapLevels[0].cbSurface, pIndexSurface->pMipmapLevels[0].pSurfaceData, GL_DYNAMIC_DRAW);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
@@ -7365,27 +6202,16 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
pIndexSurface->flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER;
-#ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
pState->ext.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OPENGL_INVALID_ID);
VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
pContext = pState->papContexts[cid];
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-#endif
}
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- else
-#endif
- {
- Assert(pIndexSurface->fDirty == false);
+ Assert(pIndexSurface->fDirty == false);
- pState->ext.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pIndexSurface->oglId.buffer);
- VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
- }
-#ifndef VMSVGA3D_OGL_WITH_SHARED_CTX
- LogFlow(("vmsvga3dDrawPrimitives: sid=%x idAssociatedContext %#x -> %#x\n", pIndexSurface->id, pIndexSurface->idAssociatedContext, pContext->id));
- pIndexSurface->idAssociatedContext = pContext->id;
-#endif
+ pState->ext.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pIndexSurface->oglId.buffer);
+ VMSVGA3D_CHECK_LAST_ERROR(pState, pContext);
}
if (!pIndexSurface)
@@ -7396,7 +6222,7 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
}
else
{
- Assert(pRange[iPrimitive].indexBias >= 0); /* @todo */
+ Assert(pRange[iPrimitive].indexBias >= 0); /** @todo indexBias */
Assert(pRange[iPrimitive].indexWidth == pRange[iPrimitive].indexArray.stride);
/* Render with an index buffer */
@@ -7499,7 +6325,7 @@ int vmsvga3dShaderDefine(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSha
{
PVMSVGA3DCONTEXT pContext;
PVMSVGA3DSHADER pShader;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc;
@@ -7599,7 +6425,7 @@ int vmsvga3dShaderDefine(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSha
int vmsvga3dShaderDestroy(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dShaderType type)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
PVMSVGA3DSHADER pShader = NULL;
int rc;
@@ -7652,18 +6478,19 @@ int vmsvga3dShaderDestroy(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSh
int vmsvga3dShaderSet(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t cid, SVGA3dShaderType type, uint32_t shid)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc;
Log(("vmsvga3dShaderSet cid=%x type=%s shid=%d\n", cid, (type == SVGA3D_SHADERTYPE_VS) ? "VERTEX" : "PIXEL", shid));
- if ( !pContext
+ if ( !pContext
&& cid < pState->cContexts
&& pState->papContexts[cid]->id == cid)
pContext = pState->papContexts[cid];
- else
+ else if (!pContext)
{
+ AssertMsgFailed(("cid=%#x cContexts=%#x\n", cid, pState->cContexts));
Log(("vmsvga3dShaderSet invalid context id!\n"));
return VERR_INVALID_PARAMETER;
}
@@ -7727,7 +6554,7 @@ int vmsvga3dShaderSet(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t cid,
int vmsvga3dShaderSetConst(PVGASTATE pThis, uint32_t cid, uint32_t reg, SVGA3dShaderType type, SVGA3dShaderConstType ctype, uint32_t cRegisters, uint32_t *pValues)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc;
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.h b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-savedstate.cpp
similarity index 72%
rename from src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.h
rename to src/VBox/Devices/Graphics/DevVGA-SVGA3d-savedstate.cpp
index 6e29143..b5d976e 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.h
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-savedstate.cpp
@@ -1,8 +1,10 @@
+/* $Id: DevVGA-SVGA3d-savedstate.cpp $ */
/** @file
- * VMware SVGA device -- 3D part
+ * DevSVGA3d - VMWare SVGA device, 3D parts - Saved state and assocated stuff.
*/
+
/*
- * Copyright (C) 2013 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -12,18 +14,150 @@
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-#ifndef __DEVVMWARE3D_STATE_H__
-#define __DEVVMWARE3D_STATE_H__
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+
+#include <VBox/vmm/pgm.h> /* required by DevVGA.h */
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
+
+/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
+#include "DevVGA.h"
+
+#include "DevVGA-SVGA.h"
+#include "DevVGA-SVGA3d.h"
+#define VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+#include "DevVGA-SVGA3d-internal.h"
+
+
+
+/**
+ * Reinitializes an active context.
+ *
+ * @returns VBox status code.
+ * @param pThis The VMSVGA device state.
+ * @param pContext The freshly loaded context to reinitialize.
+ */
+static int vmsvga3dLoadReinitContext(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext)
+{
+ int rc;
+ uint32_t cid = pContext->id;
+ Assert(cid != SVGA3D_INVALID_ID);
+
+ /* First set the render targets as they change the internal state (reset viewport etc) */
+ Log(("vmsvga3dLoadReinitContext: Recreate render targets BEGIN [cid=%#x]\n", cid));
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aRenderTargets); j++)
+ {
+ if (pContext->state.aRenderTargets[j] != SVGA3D_INVALID_ID)
+ {
+ SVGA3dSurfaceImageId target;
+
+ target.sid = pContext->state.aRenderTargets[j];
+ target.face = 0;
+ target.mipmap = 0;
+ rc = vmsvga3dSetRenderTarget(pThis, cid, (SVGA3dRenderTargetType)j, target);
+ AssertRCReturn(rc, rc);
+ }
+ }
+ Log(("vmsvga3dLoadReinitContext: Recreate render targets END\n"));
+
+ /* Recreate the render state */
+ Log(("vmsvga3dLoadReinitContext: Recreate render state BEGIN\n"));
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aRenderState); j++)
+ {
+ SVGA3dRenderState *pRenderState = &pContext->state.aRenderState[j];
+
+ if (pRenderState->state != SVGA3D_RS_INVALID)
+ vmsvga3dSetRenderState(pThis, pContext->id, 1, pRenderState);
+ }
+ Log(("vmsvga3dLoadReinitContext: Recreate render state END\n"));
+
+ /* Recreate the texture state */
+ Log(("vmsvga3dLoadReinitContext: Recreate texture state BEGIN\n"));
+ for (uint32_t iStage = 0; iStage < SVGA3D_MAX_TEXTURE_STAGE; iStage++)
+ {
+ for (uint32_t j = 0; j < SVGA3D_TS_MAX; j++)
+ {
+ SVGA3dTextureState *pTextureState = &pContext->state.aTextureState[iStage][j];
+
+ if (pTextureState->name != SVGA3D_TS_INVALID)
+ vmsvga3dSetTextureState(pThis, pContext->id, 1, pTextureState);
+ }
+ }
+ Log(("vmsvga3dLoadReinitContext: Recreate texture state END\n"));
+
+ /* Reprogram the clip planes. */
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aClipPlane); j++)
+ {
+ if (pContext->state.aClipPlane[j].fValid == true)
+ vmsvga3dSetClipPlane(pThis, cid, j, pContext->state.aClipPlane[j].plane);
+ }
+
+ /* Reprogram the light data. */
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aLightData); j++)
+ {
+ if (pContext->state.aLightData[j].fValidData == true)
+ vmsvga3dSetLightData(pThis, cid, j, &pContext->state.aLightData[j].data);
+ if (pContext->state.aLightData[j].fEnabled)
+ vmsvga3dSetLightEnabled(pThis, cid, j, true);
+ }
+
+ /* Recreate the transform state. */
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_TRANSFORM)
+ {
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aTransformState); j++)
+ {
+ if (pContext->state.aTransformState[j].fValid == true)
+ vmsvga3dSetTransform(pThis, cid, (SVGA3dTransformType)j, pContext->state.aTransformState[j].matrix);
+ }
+ }
+
+ /* Reprogram the material data. */
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_MATERIAL)
+ {
+ for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aMaterial); j++)
+ {
+ if (pContext->state.aMaterial[j].fValid == true)
+ vmsvga3dSetMaterial(pThis, cid, (SVGA3dFace)j, &pContext->state.aMaterial[j].material);
+ }
+ }
+
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_SCISSORRECT)
+ vmsvga3dSetScissorRect(pThis, cid, &pContext->state.RectScissor);
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_ZRANGE)
+ vmsvga3dSetZRange(pThis, cid, pContext->state.zRange);
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_VIEWPORT)
+ vmsvga3dSetViewPort(pThis, cid, &pContext->state.RectViewPort);
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_VERTEXSHADER)
+ vmsvga3dShaderSet(pThis, pContext, cid, SVGA3D_SHADERTYPE_VS, pContext->state.shidVertex);
+ if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_PIXELSHADER)
+ vmsvga3dShaderSet(pThis, pContext, cid, SVGA3D_SHADERTYPE_PS, pContext->state.shidPixel);
+
+ Log(("vmsvga3dLoadReinitContext: returns [cid=%#x]\n", cid));
+ return VINF_SUCCESS;
+}
int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc;
uint32_t cContexts, cSurfaces;
+ LogFlow(("vmsvga3dLoadExec:\n"));
+#ifndef RT_OS_DARWIN /** @todo r=bird: this is normally done on the EMT, so for DARWIN we do that when loading saved state too now. See DevVGA-SVGA.cpp */
/* Must initialize now as the recreation calls below rely on an initialized 3d subsystem. */
vmsvga3dPowerOn(pThis);
+#endif
/* Get the generic 3d state first. */
rc = SSMR3GetStructEx(pSSM, pState, sizeof(*pState), 0, g_aVMSVGA3DSTATEFields, NULL);
@@ -47,11 +181,27 @@ int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32
if (cid != SVGA3D_INVALID_ID)
{
uint32_t cPixelShaderConst, cVertexShaderConst, cPixelShaders, cVertexShaders;
+ LogFlow(("vmsvga3dLoadExec: Loading cid=%#x\n", cid));
- rc = vmsvga3dContextDefine(pThis, cid);
- AssertRCReturn(rc, rc);
+#ifdef VMSVGA3D_OPENGL
+ if (cid == VMSVGA3D_SHARED_CTX_ID)
+ {
+ i--; /* Not included in cContexts. */
+ pContext = &pState->SharedCtx;
+ if (pContext->id != VMSVGA3D_SHARED_CTX_ID)
+ {
+ rc = vmsvga3dContextDefineOgl(pThis, VMSVGA3D_SHARED_CTX_ID, VMSVGA3D_DEF_CTX_F_SHARED_CTX);
+ AssertRCReturn(rc, rc);
+ }
+ }
+ else
+#endif
+ {
+ rc = vmsvga3dContextDefine(pThis, cid);
+ AssertRCReturn(rc, rc);
- pContext = pState->papContexts[i];
+ pContext = pState->papContexts[i];
+ }
AssertReturn(pContext->id == cid, VERR_INTERNAL_ERROR);
rc = SSMR3GetStructEx(pSSM, pContext, sizeof(*pContext), 0, g_aVMSVGA3DCONTEXTFields, NULL);
@@ -157,10 +307,15 @@ int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32
AssertRCReturn(rc, rc);
}
}
-
}
}
+#ifdef VMSVGA3D_OPENGL
+ /* Make the shared context the current one. */
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, &pState->SharedCtx);
+#endif
+
/* Fetch all surfaces. */
for (uint32_t i = 0; i < cSurfaces; i++)
{
@@ -173,6 +328,7 @@ int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32
if (sid != SVGA3D_INVALID_ID)
{
VMSVGA3DSURFACE surface;
+ LogFlow(("vmsvga3dLoadExec: Loading sid=%#x\n", sid));
/* Fetch the surface structure first. */
rc = SSMR3GetStructEx(pSSM, &surface, sizeof(surface), 0, g_aVMSVGA3DSURFACEFields, NULL);
@@ -220,7 +376,7 @@ int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32
Assert(pMipmapLevel->cbSurface);
pMipmapLevel->pSurfaceData = RTMemAllocZ(pMipmapLevel->cbSurface);
AssertReturn(pMipmapLevel->pSurfaceData, VERR_NO_MEMORY);
-
+
/* Fetch the data present boolean first. */
rc = SSMR3GetBool(pSSM, &fDataPresent);
AssertRCReturn(rc, rc);
@@ -242,110 +398,114 @@ int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32
}
}
+#ifdef VMSVGA3D_OPENGL
+ /* Reinitialize the shared context. */
+ LogFlow(("vmsvga3dLoadExec: pState->SharedCtx.id=%#x\n", pState->SharedCtx.id));
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ {
+ rc = vmsvga3dLoadReinitContext(pThis, &pState->SharedCtx);
+ AssertRCReturn(rc, rc);
+ }
+#endif
+
/* Reinitialize all active contexts. */
for (uint32_t i = 0; i < pState->cContexts; i++)
{
PVMSVGA3DCONTEXT pContext = pState->papContexts[i];
- uint32_t cid = pContext->id;
+ if (pContext->id != SVGA3D_INVALID_ID)
+ {
+ rc = vmsvga3dLoadReinitContext(pThis, pContext);
+ AssertRCReturn(rc, rc);
+ }
+ }
- if (cid != SVGA3D_INVALID_ID)
+ LogFlow(("vmsvga3dLoadExec: return success\n"));
+ return VINF_SUCCESS;
+}
+
+
+static int vmsvga3dSaveContext(PVGASTATE pThis, PSSMHANDLE pSSM, PVMSVGA3DCONTEXT pContext)
+{
+ uint32_t cid = pContext->id;
+
+ /* Save the id first. */
+ int rc = SSMR3PutU32(pSSM, cid);
+ AssertRCReturn(rc, rc);
+
+ if (cid != SVGA3D_INVALID_ID)
+ {
+ /* Save a copy of the context structure first. */
+ rc = SSMR3PutStructEx(pSSM, pContext, sizeof(*pContext), 0, g_aVMSVGA3DCONTEXTFields, NULL);
+ AssertRCReturn(rc, rc);
+
+ /* Save all pixel shaders. */
+ for (uint32_t j = 0; j < pContext->cPixelShaders; j++)
{
- /* First set the render targets as they change the internal state (reset viewport etc) */
- Log(("vmsvga3dLoadExec: Recreate render targets BEGIN\n"));
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aRenderTargets); j++)
- {
- if (pContext->state.aRenderTargets[j] != SVGA3D_INVALID_ID)
- {
- SVGA3dSurfaceImageId target;
+ PVMSVGA3DSHADER pShader = &pContext->paPixelShader[j];
- target.sid = pContext->state.aRenderTargets[j];
- target.face = 0;
- target.mipmap = 0;
- rc = vmsvga3dSetRenderTarget(pThis, cid, (SVGA3dRenderTargetType)j, target);
- AssertRCReturn(rc, rc);
- }
- }
- Log(("vmsvga3dLoadExec: Recreate render targets END\n"));
+ /* Save the id first. */
+ rc = SSMR3PutU32(pSSM, pShader->id);
+ AssertRCReturn(rc, rc);
- /* Recreate the render state */
- Log(("vmsvga3dLoadExec: Recreate render state BEGIN\n"));
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aRenderState); j++)
+ if (pShader->id != SVGA3D_INVALID_ID)
{
- SVGA3dRenderState *pRenderState = &pContext->state.aRenderState[j];
+ uint32_t cbData = pShader->cbData;
- if (pRenderState->state != SVGA3D_RS_INVALID)
- vmsvga3dSetRenderState(pThis, pContext->id, 1, pRenderState);
+ /* Save a copy of the shader struct. */
+ rc = SSMR3PutStructEx(pSSM, pShader, sizeof(*pShader), 0, g_aVMSVGA3DSHADERFields, NULL);
+ AssertRCReturn(rc, rc);
+
+ Log(("Save pixelshader shid=%d with %x bytes code.\n", pShader->id, cbData));
+ rc = SSMR3PutMem(pSSM, pShader->pShaderProgram, cbData);
+ AssertRCReturn(rc, rc);
}
- Log(("vmsvga3dLoadExec: Recreate render state END\n"));
+ }
- /* Recreate the texture state */
- Log(("vmsvga3dLoadExec: Recreate texture state BEGIN\n"));
- for (uint32_t iStage = 0; iStage < SVGA3D_MAX_TEXTURE_STAGE; iStage++)
- {
- for (uint32_t j = 0; j < SVGA3D_TS_MAX; j++)
- {
- SVGA3dTextureState *pTextureState = &pContext->state.aTextureState[iStage][j];
+ /* Save all vertex shaders. */
+ for (uint32_t j = 0; j < pContext->cVertexShaders; j++)
+ {
+ PVMSVGA3DSHADER pShader = &pContext->paVertexShader[j];
- if (pTextureState->name != SVGA3D_TS_INVALID)
- vmsvga3dSetTextureState(pThis, pContext->id, 1, pTextureState);
- }
- }
- Log(("vmsvga3dLoadExec: Recreate texture state END\n"));
+ /* Save the id first. */
+ rc = SSMR3PutU32(pSSM, pShader->id);
+ AssertRCReturn(rc, rc);
- /* Reprogram the clip planes. */
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aClipPlane); j++)
+ if (pShader->id != SVGA3D_INVALID_ID)
{
- if (pContext->state.aClipPlane[j].fValid == true)
- vmsvga3dSetClipPlane(pThis, cid, j, pContext->state.aClipPlane[j].plane);
- }
+ uint32_t cbData = pShader->cbData;
- /* Reprogram the light data. */
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aLightData); j++)
- {
- if (pContext->state.aLightData[j].fValidData == true)
- vmsvga3dSetLightData(pThis, cid, j, &pContext->state.aLightData[j].data);
- if (pContext->state.aLightData[j].fEnabled)
- vmsvga3dSetLightEnabled(pThis, cid, j, true);
- }
+ /* Save a copy of the shader struct. */
+ rc = SSMR3PutStructEx(pSSM, pShader, sizeof(*pShader), 0, g_aVMSVGA3DSHADERFields, NULL);
+ AssertRCReturn(rc, rc);
- /* Recreate the transform state. */
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_TRANSFORM)
- {
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aTransformState); j++)
- {
- if (pContext->state.aTransformState[j].fValid == true)
- vmsvga3dSetTransform(pThis, cid, (SVGA3dTransformType)j, pContext->state.aTransformState[j].matrix);
- }
+ Log(("Save vertex shader shid=%d with %x bytes code.\n", pShader->id, cbData));
+ /* Fetch the shader code and save it. */
+ rc = SSMR3PutMem(pSSM, pShader->pShaderProgram, cbData);
+ AssertRCReturn(rc, rc);
}
+ }
- /* Reprogram the material data. */
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_MATERIAL)
- {
- for (uint32_t j = 0; j < RT_ELEMENTS(pContext->state.aMaterial); j++)
- {
- if (pContext->state.aMaterial[j].fValid == true)
- vmsvga3dSetMaterial(pThis, cid, (SVGA3dFace)j, &pContext->state.aMaterial[j].material);
- }
- }
+ /* Save pixel shader constants. */
+ for (uint32_t j = 0; j < pContext->state.cPixelShaderConst; j++)
+ {
+ rc = SSMR3PutStructEx(pSSM, &pContext->state.paPixelShaderConst[j], sizeof(pContext->state.paPixelShaderConst[j]), 0, g_aVMSVGASHADERCONSTFields, NULL);
+ AssertRCReturn(rc, rc);
+ }
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_SCISSORRECT)
- vmsvga3dSetScissorRect(pThis, cid, &pContext->state.RectScissor);
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_ZRANGE)
- vmsvga3dSetZRange(pThis, cid, pContext->state.zRange);
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_VIEWPORT)
- vmsvga3dSetViewPort(pThis, cid, &pContext->state.RectViewPort);
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_VERTEXSHADER)
- vmsvga3dShaderSet(pThis, pContext, cid, SVGA3D_SHADERTYPE_VS, pContext->state.shidVertex);
- if (pContext->state.u32UpdateFlags & VMSVGA3D_UPDATE_PIXELSHADER)
- vmsvga3dShaderSet(pThis, pContext, cid, SVGA3D_SHADERTYPE_PS, pContext->state.shidPixel);
+ /* Save vertex shader constants. */
+ for (uint32_t j = 0; j < pContext->state.cVertexShaderConst; j++)
+ {
+ rc = SSMR3PutStructEx(pSSM, &pContext->state.paVertexShaderConst[j], sizeof(pContext->state.paVertexShaderConst[j]), 0, g_aVMSVGASHADERCONSTFields, NULL);
+ AssertRCReturn(rc, rc);
}
}
+
return VINF_SUCCESS;
}
int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
int rc;
@@ -353,83 +513,20 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
rc = SSMR3PutStructEx(pSSM, pState, sizeof(*pState), 0, g_aVMSVGA3DSTATEFields, NULL);
AssertRCReturn(rc, rc);
+#ifdef VMSVGA3D_OPENGL
+ /* Save the shared context. */
+ if (pState->SharedCtx.id == VMSVGA3D_SHARED_CTX_ID)
+ {
+ rc = vmsvga3dSaveContext(pThis, pSSM, &pState->SharedCtx);
+ AssertRCReturn(rc, rc);
+ }
+#endif
+
/* Save all active contexts. */
for (uint32_t i = 0; i < pState->cContexts; i++)
{
- PVMSVGA3DCONTEXT pContext = pState->papContexts[i];
- uint32_t cid = pContext->id;
-
- /* Save the id first. */
- rc = SSMR3PutU32(pSSM, cid);
+ rc = vmsvga3dSaveContext(pThis, pSSM, pState->papContexts[i]);
AssertRCReturn(rc, rc);
-
- if (cid != SVGA3D_INVALID_ID)
- {
- /* Save a copy of the context structure first. */
- rc = SSMR3PutStructEx(pSSM, pContext, sizeof(*pContext), 0, g_aVMSVGA3DCONTEXTFields, NULL);
- AssertRCReturn(rc, rc);
-
- /* Save all pixel shaders. */
- for (uint32_t j = 0; j < pContext->cPixelShaders; j++)
- {
- PVMSVGA3DSHADER pShader = &pContext->paPixelShader[j];
-
- /* Save the id first. */
- rc = SSMR3PutU32(pSSM, pShader->id);
- AssertRCReturn(rc, rc);
-
- if (pShader->id != SVGA3D_INVALID_ID)
- {
- uint32_t cbData = pShader->cbData;
-
- /* Save a copy of the shader struct. */
- rc = SSMR3PutStructEx(pSSM, pShader, sizeof(*pShader), 0, g_aVMSVGA3DSHADERFields, NULL);
- AssertRCReturn(rc, rc);
-
- Log(("Save pixelshader shid=%d with %x bytes code.\n", pShader->id, cbData));
- rc = SSMR3PutMem(pSSM, pShader->pShaderProgram, cbData);
- AssertRCReturn(rc, rc);
- }
- }
-
- /* Save all vertex shaders. */
- for (uint32_t j = 0; j < pContext->cVertexShaders; j++)
- {
- PVMSVGA3DSHADER pShader = &pContext->paVertexShader[j];
-
- /* Save the id first. */
- rc = SSMR3PutU32(pSSM, pShader->id);
- AssertRCReturn(rc, rc);
-
- if (pShader->id != SVGA3D_INVALID_ID)
- {
- uint32_t cbData = pShader->cbData;
-
- /* Save a copy of the shader struct. */
- rc = SSMR3PutStructEx(pSSM, pShader, sizeof(*pShader), 0, g_aVMSVGA3DSHADERFields, NULL);
- AssertRCReturn(rc, rc);
-
- Log(("Save vertex shader shid=%d with %x bytes code.\n", pShader->id, cbData));
- /* Fetch the shader code and save it. */
- rc = SSMR3PutMem(pSSM, pShader->pShaderProgram, cbData);
- AssertRCReturn(rc, rc);
- }
- }
-
- /* Save pixel shader constants. */
- for (uint32_t j = 0; j < pContext->state.cPixelShaderConst; j++)
- {
- rc = SSMR3PutStructEx(pSSM, &pContext->state.paPixelShaderConst[j], sizeof(pContext->state.paPixelShaderConst[j]), 0, g_aVMSVGASHADERCONSTFields, NULL);
- AssertRCReturn(rc, rc);
- }
-
- /* Save vertex shader constants. */
- for (uint32_t j = 0; j < pContext->state.cVertexShaderConst; j++)
- {
- rc = SSMR3PutStructEx(pSSM, &pContext->state.paVertexShaderConst[j], sizeof(pContext->state.paVertexShaderConst[j]), 0, g_aVMSVGASHADERCONSTFields, NULL);
- AssertRCReturn(rc, rc);
- }
- }
}
/* Save all active surfaces. */
@@ -574,7 +671,7 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
NULL,
D3DLOCK_READONLY);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSaveExec: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
-
+
/* Copy the data one line at a time in case the internal pitch is different. */
for (uint32_t j = 0; j < pMipmapLevel->size.height; j++)
{
@@ -607,7 +704,7 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
if (fVertex)
hr = pSurface->u.pVertexBuffer->Lock(0, 0, (void **)&pD3DData, D3DLOCK_READONLY);
- else
+ else
hr = pSurface->u.pIndexBuffer->Lock(0, 0, (void **)&pD3DData, D3DLOCK_READONLY);
AssertMsg(hr == D3D_OK, ("vmsvga3dSaveExec: Lock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
@@ -647,21 +744,8 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
#elif defined(VMSVGA3D_OPENGL)
void *pData = NULL;
-# ifdef VMSVGA3D_OGL_WITH_SHARED_CTX
PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-# else
- /* @todo stricter checks for associated context */
- uint32_t cid = pSurface->idAssociatedContext;
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSaveExec: invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
- VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
-# endif
Assert(pMipmapLevel->cbSurface);
@@ -695,16 +779,16 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
/* Set row length and alignment of the output data. */
VMSVGAPACKPARAMS SavedParams;
- vmsvga3dSetPackParams(pState, pContext, pSurface, &SavedParams);
+ vmsvga3dOglSetPackParams(pState, pContext, pSurface, &SavedParams);
glGetTexImage(GL_TEXTURE_2D,
i,
- pSurface->formatGL,
- pSurface->typeGL,
+ pSurface->formatGL,
+ pSurface->typeGL,
pData);
VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext);
- vmsvga3dRestorePackParams(pState, pContext, pSurface, &SavedParams);
+ vmsvga3dOglRestorePackParams(pState, pContext, pSurface, &SavedParams);
/* Data follows */
rc = SSMR3PutBool(pSSM, true);
@@ -761,7 +845,7 @@ int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM)
return VINF_SUCCESS;
}
-static uint32_t vmsvga3dSaveShaderConst(PVMSVGA3DCONTEXT pContext, uint32_t reg, SVGA3dShaderType type, SVGA3dShaderConstType ctype, uint32_t val1, uint32_t val2, uint32_t val3, uint32_t val4)
+uint32_t vmsvga3dSaveShaderConst(PVMSVGA3DCONTEXT pContext, uint32_t reg, SVGA3dShaderType type, SVGA3dShaderConstType ctype, uint32_t val1, uint32_t val2, uint32_t val3, uint32_t val4)
{
/* Choose a sane upper limit. */
AssertReturn(reg < _32K, VERR_INVALID_PARAMETER);
@@ -807,5 +891,3 @@ static uint32_t vmsvga3dSaveShaderConst(PVMSVGA3DCONTEXT pContext, uint32_t reg,
return VINF_SUCCESS;
}
-
-#endif /* __DEVVMWARE3D_STATE_H__ */
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.cpp
index cb3ae4e..909cfcc 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-shared.cpp
@@ -15,9 +15,9 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
#include <VBox/vmm/pdmdev.h>
#include <VBox/version.h>
@@ -31,30 +31,23 @@
#include <iprt/mem.h>
#include <iprt/avl.h>
-#include <VBox/VMMDev.h>
-#include <VBox/VBoxVideo.h>
-#include <VBox/bioslogo.h>
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
#include "DevVGA.h"
#include "DevVGA-SVGA.h"
#include "DevVGA-SVGA3d.h"
-#include "vmsvga/svga_reg.h"
-#include "vmsvga/svga3d_reg.h"
-#include "vmsvga/svga3d_shaderdefs.h"
+#define VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+#include "DevVGA-SVGA3d-internal.h"
#ifdef RT_OS_WINDOWS
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-#define VMSVGA3D_WNDCLASSNAME "VMSVGA3DWNDCLS"
+# define VMSVGA3D_WNDCLASSNAME "VMSVGA3DWNDCLS"
static LONG WINAPI vmsvga3dWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-#endif
-#ifdef RT_OS_WINDOWS
+
/**
* Send a message to the async window thread and wait for a reply
*
@@ -145,35 +138,34 @@ DECLCALLBACK(int) vmsvga3dWindowThread(RTTHREAD ThreadSelf, void *pvUser)
pCS->cx = rectClient.right - rectClient.left;
pCS->cy = rectClient.bottom - rectClient.top;
#endif
- *pHwnd = CreateWindowEx(pCS->dwExStyle,
- VMSVGA3D_WNDCLASSNAME,
- pCS->lpszName,
+ *pHwnd = CreateWindowEx(pCS->dwExStyle,
+ VMSVGA3D_WNDCLASSNAME,
+ pCS->lpszName,
pCS->style,
#ifdef DEBUG_GFX_WINDOW
0,
0,
#else
- pCS->x,
- pCS->y,
+ pCS->x,
+ pCS->y,
#endif
- pCS->cx,
+ pCS->cx,
pCS->cy,
#ifdef DEBUG_GFX_WINDOW
0,
#else
- pCS->hwndParent,
+ pCS->hwndParent,
#endif
- pCS->hMenu,
- pCS->hInstance,
+ pCS->hMenu,
+ pCS->hInstance,
NULL);
- AssertMsg(*pHwnd, ("CreateWindowEx %x %s %s %x (%d,%d)(%d,%d), %x %x %x error=%x\n", pCS->dwExStyle, pCS->lpszName, VMSVGA3D_WNDCLASSNAME, pCS->style, pCS->x,
+ AssertMsg(*pHwnd, ("CreateWindowEx %x %s %s %x (%d,%d)(%d,%d), %x %x %x error=%x\n", pCS->dwExStyle, pCS->lpszName, VMSVGA3D_WNDCLASSNAME, pCS->style, pCS->x,
pCS->y, pCS->cx, pCS->cy,pCS->hwndParent, pCS->hMenu, pCS->hInstance, GetLastError()));
/* Signal to the caller that we're done. */
RTSemEventSignal(WndRequestSem);
continue;
}
- else
if (msg.message == WM_VMSVGA3D_DESTROYWINDOW)
{
BOOL ret = DestroyWindow((HWND)msg.wParam);
@@ -182,7 +174,6 @@ DECLCALLBACK(int) vmsvga3dWindowThread(RTTHREAD ThreadSelf, void *pvUser)
RTSemEventSignal(WndRequestSem);
continue;
}
- else
if (msg.message == WM_VMSVGA3D_RESIZEWINDOW)
{
HWND hwnd = (HWND)msg.wParam;
@@ -227,18 +218,59 @@ static LONG WINAPI vmsvga3dWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
switch (uMsg)
{
case WM_CLOSE:
+ Log6(("vmsvga3dWndProc(%p): WM_CLOSE\n", hwnd));
break;
case WM_DESTROY:
+ Log6(("vmsvga3dWndProc(%p): WM_DESTROY\n", hwnd));
break;
case WM_NCHITTEST:
+ Log6(("vmsvga3dWndProc(%p): WM_NCHITTEST\n", hwnd));
return HTNOWHERE;
+
+# if 0 /* flicker experiment, no help here. */
+ case WM_PAINT:
+ Log6(("vmsvga3dWndProc(%p): WM_PAINT %p %p\n", hwnd, wParam, lParam));
+ ValidateRect(hwnd, NULL);
+ return 0;
+ case WM_ERASEBKGND:
+ Log6(("vmsvga3dWndProc(%p): WM_ERASEBKGND %p %p\n", hwnd, wParam, lParam));
+ return TRUE;
+ case WM_NCPAINT:
+ Log6(("vmsvga3dWndProc(%p): WM_NCPAINT %p %p\n", hwnd, wParam, lParam));
+ break;
+ case WM_WINDOWPOSCHANGING:
+ {
+ PWINDOWPOS pPos = (PWINDOWPOS)lParam;
+ Log6(("vmsvga3dWndProc(%p): WM_WINDOWPOSCHANGING %p %p pos=(%d,%d) size=(%d,%d) flags=%#x\n",
+ hwnd, wParam, lParam, pPos->x, pPos->y, pPos->cx, pPos->cy, pPos->flags));
+ break;
+ }
+ case WM_WINDOWPOSCHANGED:
+ {
+ PWINDOWPOS pPos = (PWINDOWPOS)lParam;
+ Log6(("vmsvga3dWndProc(%p): WM_WINDOWPOSCHANGED %p %p pos=(%d,%d) size=(%d,%d) flags=%#x\n",
+ hwnd, wParam, lParam, pPos->x, pPos->y, pPos->cx, pPos->cy, pPos->flags));
+ break;
+ }
+ case WM_MOVE:
+ Log6(("vmsvga3dWndProc(%p): WM_MOVE %p %p\n", hwnd, wParam, lParam));
+ break;
+ case WM_SIZE:
+ Log6(("vmsvga3dWndProc(%p): WM_SIZE %p %p\n", hwnd, wParam, lParam));
+ break;
+
+ default:
+ Log6(("vmsvga3dWndProc(%p): %#x %p %p\n", hwnd, uMsg, wParam, lParam));
+# endif
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
+
#endif /* RT_OS_WINDOWS */
+
/**
* Calculate the size of one pixel
*/
@@ -340,11 +372,14 @@ uint32_t vmsvga3dSurfaceFormatSize(SVGA3dSurfaceFormat format)
return 32;
case SVGA3D_A16B16G16R16:
return 8;
+
+ default:
+ AssertFailedReturn(4);
}
- AssertFailedReturn(4);
}
#ifdef LOG_ENABLED
+
const char *vmsvga3dGetCapString(uint32_t idxCap)
{
switch (idxCap)
@@ -579,7 +614,7 @@ const char *vmsvga3dGetRenderStateName(uint32_t state)
{
switch (state)
{
- case SVGA3D_RS_ZENABLE: /* SVGA3dBool */
+ case SVGA3D_RS_ZENABLE: /* SVGA3dBool */
return "SVGA3D_RS_ZENABLE";
case SVGA3D_RS_ZWRITEENABLE: /* SVGA3dBool */
return "SVGA3D_RS_ZWRITEENABLE";
@@ -991,114 +1026,6 @@ const char *vmsvgaDeclType2String(SVGA3dDeclType type)
}
}
-const char *vmsvgaSurfaceType2String(SVGA3dSurfaceFormat format)
-{
- switch (format)
- {
- case SVGA3D_X8R8G8B8:
- return "SVGA3D_X8R8G8B8";
- case SVGA3D_A8R8G8B8:
- return "SVGA3D_A8R8G8B8";
- case SVGA3D_R5G6B5:
- return "SVGA3D_R5G6B5";
- case SVGA3D_X1R5G5B5:
- return "SVGA3D_X1R5G5B5";
- case SVGA3D_A1R5G5B5:
- return "SVGA3D_A1R5G5B5";
- case SVGA3D_A4R4G4B4:
- return "SVGA3D_A4R4G4B4";
- case SVGA3D_Z_D32:
- return "SVGA3D_Z_D32";
- case SVGA3D_Z_D16:
- return "SVGA3D_Z_D16";
- case SVGA3D_Z_D24S8:
- return "SVGA3D_Z_D24S8";
- case SVGA3D_Z_D15S1:
- return "SVGA3D_Z_D15S1";
- case SVGA3D_Z_D24X8:
- return "SVGA3D_Z_D24X8";
- case SVGA3D_Z_DF16:
- return "SVGA3D_Z_DF16";
- case SVGA3D_Z_DF24:
- return "SVGA3D_Z_DF24";
- case SVGA3D_Z_D24S8_INT:
- return "SVGA3D_Z_D24S8_INT";
- case SVGA3D_LUMINANCE8:
- return "SVGA3D_LUMINANCE8";
- case SVGA3D_LUMINANCE4_ALPHA4:
- return "SVGA3D_LUMINANCE4_ALPHA4";
- case SVGA3D_LUMINANCE16:
- return "SVGA3D_LUMINANCE16";
- case SVGA3D_LUMINANCE8_ALPHA8:
- return "SVGA3D_LUMINANCE8_ALPHA8";
- case SVGA3D_DXT1:
- return "SVGA3D_DXT1";
- case SVGA3D_DXT2:
- return "SVGA3D_DXT2";
- case SVGA3D_DXT3:
- return "SVGA3D_DXT3";
- case SVGA3D_DXT4:
- return "SVGA3D_DXT4";
- case SVGA3D_DXT5:
- return "SVGA3D_DXT5";
- case SVGA3D_BUMPU8V8:
- return "SVGA3D_BUMPU8V8";
- case SVGA3D_BUMPL6V5U5:
- return "SVGA3D_BUMPL6V5U5";
- case SVGA3D_BUMPX8L8V8U8:
- return "SVGA3D_BUMPX8L8V8U8";
- case SVGA3D_BUMPL8V8U8:
- return "SVGA3D_BUMPL8V8U8";
- case SVGA3D_V8U8:
- return "SVGA3D_V8U8";
- case SVGA3D_Q8W8V8U8:
- return "SVGA3D_Q8W8V8U8";
- case SVGA3D_CxV8U8:
- return "SVGA3D_CxV8U8";
- case SVGA3D_X8L8V8U8:
- return "SVGA3D_X8L8V8U8";
- case SVGA3D_A2W10V10U10:
- return "SVGA3D_A2W10V10U10";
- case SVGA3D_ARGB_S10E5:
- return "SVGA3D_ARGB_S10E5";
- case SVGA3D_ARGB_S23E8:
- return "SVGA3D_ARGB_S23E8";
- case SVGA3D_A2R10G10B10:
- return "SVGA3D_A2R10G10B10";
- case SVGA3D_ALPHA8:
- return "SVGA3D_ALPHA8";
- case SVGA3D_R_S10E5:
- return "SVGA3D_R_S10E5";
- case SVGA3D_R_S23E8:
- return "SVGA3D_R_S23E8";
- case SVGA3D_RG_S10E5:
- return "SVGA3D_RG_S10E5";
- case SVGA3D_RG_S23E8:
- return "SVGA3D_RG_S23E8";
- case SVGA3D_BUFFER:
- return "SVGA3D_BUFFER";
- case SVGA3D_V16U16:
- return "SVGA3D_V16U16";
- case SVGA3D_G16R16:
- return "SVGA3D_G16R16";
- case SVGA3D_A16B16G16R16:
- return "SVGA3D_A16B16G16R16";
- case SVGA3D_UYVY:
- return "SVGA3D_UYVY";
- case SVGA3D_YUY2:
- return "SVGA3D_YUY2";
- case SVGA3D_NV12:
- return "SVGA3D_NV12";
- case SVGA3D_AYUV:
- return "SVGA3D_AYUV";
- case SVGA3D_BC4_UNORM:
- return "SVGA3D_BC4_UNORM";
- case SVGA3D_BC5_UNORM:
- return "SVGA3D_BC5_UNORM";
- }
- return "UNKNOWN!!";
-}
-
const char *vmsvga3dPrimitiveType2String(SVGA3dPrimitiveType PrimitiveType)
{
switch (PrimitiveType)
@@ -1121,3 +1048,4 @@ const char *vmsvga3dPrimitiveType2String(SVGA3dPrimitiveType PrimitiveType)
}
#endif /* LOG_ENABLED */
+
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win.cpp
index 1c1e46b..225487f 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d-win.cpp
@@ -15,9 +15,9 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
#include <VBox/vmm/pdmdev.h>
#include <VBox/version.h>
@@ -31,20 +31,14 @@
#include <iprt/mem.h>
#include <iprt/avl.h>
-#include <VBox/VMMDev.h>
-#include <VBox/VBoxVideo.h>
-#include <VBox/bioslogo.h>
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
#include "DevVGA.h"
#include "DevVGA-SVGA.h"
#include "DevVGA-SVGA3d.h"
-#include "vmsvga/svga_reg.h"
-#include "vmsvga/svga3d_reg.h"
-#include "vmsvga/svga3d_shaderdefs.h"
-
-#include <d3d9.h>
+#include "DevVGA-SVGA3d-internal.h"
/* Enable to disassemble defined shaders. */
#if defined(DEBUG) && 0 /* Disabled as we don't have the DirectX SDK avaible atm. */
@@ -55,326 +49,20 @@
#include <d3dx9shader.h>
#endif
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
/* Enable to render the result of DrawPrimitive in a seperate window. */
//#define DEBUG_GFX_WINDOW
-/* Enable to use Wine to convert D3D to opengl */
-//#define VBOX_VMSVGA3D_WITH_OPENGL
-
#define FOURCC_INTZ (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z')
#define FOURCC_NULL (D3DFORMAT)MAKEFOURCC('N', 'U', 'L', 'L')
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-
-typedef struct
-{
- SVGA3dSize size;
- uint32_t cbSurface;
- uint32_t cbSurfacePitch;
- void *pSurfaceData;
- bool fDirty;
-} VMSVGA3DMIPMAPLEVEL, *PVMSVGA3DMIPMAPLEVEL;
-
-/**
- * SSM descriptor table for the VMSVGA3DMIPMAPLEVEL structure.
- */
-static SSMFIELD const g_aVMSVGA3DMIPMAPLEVELFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, size),
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurface),
- SSMFIELD_ENTRY( VMSVGA3DMIPMAPLEVEL, cbSurfacePitch),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DMIPMAPLEVEL, pSurfaceData),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DMIPMAPLEVEL, fDirty),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- /* Key is context id. */
- AVLU32NODECORE Core;
- union
- {
- IDirect3DSurface9 *pSurface;
- IDirect3DTexture9 *pTexture;
- IDirect3DCubeTexture9 *pCubeTexture;
- } u;
-} VMSVGA3DSHAREDSURFACE, *PVMSVGA3DSHAREDSURFACE;
-
-typedef struct
-{
- uint32_t id;
- uint32_t idAssociatedContext;
- uint32_t flags;
- SVGA3dSurfaceFormat format;
- SVGA3dSurfaceFace faces[SVGA3D_MAX_SURFACE_FACES];
- uint32_t cFaces;
- PVMSVGA3DMIPMAPLEVEL pMipmapLevels;
- uint32_t multiSampleCount;
- SVGA3dTextureFilter autogenFilter;
- D3DFORMAT formatD3D;
- DWORD fUsageD3D;
- D3DMULTISAMPLE_TYPE multiSampleTypeD3D;
- uint32_t cbBlock; /* block/pixel size in bytes */
- /* Dirty state; surface was manually updated. */
- bool fDirty;
- /* Handle for shared objects (currently only textures & render targets). */
- HANDLE hSharedObject;
- /** Event query inserted after each GPU operation that updates or uses this surface. */
- IDirect3DQuery9 *pQuery;
- union
- {
- IDirect3DSurface9 *pSurface;
- IDirect3DCubeTexture9 *pCubeTexture;
- IDirect3DIndexBuffer9 *pIndexBuffer;
- IDirect3DTexture9 *pTexture;
- IDirect3DVertexBuffer9 *pVertexBuffer;
- } u;
- union
- {
- IDirect3DTexture9 *pTexture;
- } bounce;
- AVLU32TREE pSharedObjectTree;
- bool fStencilAsTexture;
-} VMSVGA3DSURFACE, *PVMSVGA3DSURFACE;
-
-/**
- * SSM descriptor table for the VMSVGA3DSURFACE structure.
- */
-static SSMFIELD const g_aVMSVGA3DSURFACEFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, id),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, idAssociatedContext),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, flags),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, format),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, faces),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, cFaces),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, pMipmapLevels),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, multiSampleCount),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, autogenFilter),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, format),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, formatD3D),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fUsageD3D),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, multiSampleTypeD3D),
- SSMFIELD_ENTRY( VMSVGA3DSURFACE, cbBlock),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fDirty),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, hSharedObject),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, pQuery),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, u.pSurface),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSURFACE, bounce.pTexture),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, pSharedObjectTree),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSURFACE, fStencilAsTexture),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- uint32_t id;
- uint32_t cid;
- SVGA3dShaderType type;
- uint32_t cbData;
- void *pShaderProgram;
- union
- {
- IDirect3DVertexShader9 *pVertexShader;
- IDirect3DPixelShader9 *pPixelShader;
- } u;
-} VMSVGA3DSHADER, *PVMSVGA3DSHADER;
-
-/**
- * SSM descriptor table for the VMSVGA3DSHADER structure.
- */
-static SSMFIELD const g_aVMSVGA3DSHADERFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DSHADER, id),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, cid),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, type),
- SSMFIELD_ENTRY( VMSVGA3DSHADER, cbData),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, pShaderProgram),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSHADER, u.pVertexShader),
- SSMFIELD_ENTRY_TERM()
-};
-
-typedef struct
-{
- bool fValid;
- float matrix[16];
-} VMSVGATRANSFORMSTATE, *PVMSVGATRANSFORMSTATE;
-
-typedef struct
-{
- bool fValid;
- SVGA3dMaterial material;
-} VMSVGAMATERIALSTATE, *PVMSVGAMATERIALSTATE;
-
-typedef struct
-{
- bool fValid;
- float plane[4];
-} VMSVGACLIPPLANESTATE, *PVMSVGACLIPPLANESTATE;
-
-typedef struct
-{
- bool fEnabled;
- bool fValidData;
- SVGA3dLightData data;
-} VMSVGALIGHTSTATE, *PVMSVGALIGHTSTATE;
-
-typedef struct
-{
- bool fValid;
- SVGA3dShaderConstType ctype;
- uint32_t value[4];
-} VMSVGASHADERCONST, *PVMSVGASHADERCONST;
-
-/**
- * SSM descriptor table for the VMSVGASHADERCONST structure.
- */
-static SSMFIELD const g_aVMSVGASHADERCONSTFields[] =
-{
- SSMFIELD_ENTRY( VMSVGASHADERCONST, fValid),
- SSMFIELD_ENTRY( VMSVGASHADERCONST, ctype),
- SSMFIELD_ENTRY( VMSVGASHADERCONST, value),
- SSMFIELD_ENTRY_TERM()
-};
-
-#define VMSVGA3D_UPDATE_SCISSORRECT RT_BIT(0)
-#define VMSVGA3D_UPDATE_ZRANGE RT_BIT(1)
-#define VMSVGA3D_UPDATE_VIEWPORT RT_BIT(2)
-#define VMSVGA3D_UPDATE_VERTEXSHADER RT_BIT(3)
-#define VMSVGA3D_UPDATE_PIXELSHADER RT_BIT(4)
-#define VMSVGA3D_UPDATE_TRANSFORM RT_BIT(5)
-#define VMSVGA3D_UPDATE_MATERIAL RT_BIT(6)
-
-typedef struct VMSVGA3DCONTEXT
-{
- uint32_t id;
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
- IDirect3DDevice9 *pDevice;
-#else
- IDirect3DDevice9Ex *pDevice;
-#endif
- HWND hwnd;
- /* Current active render target (if any) */
- uint32_t sidRenderTarget;
- /* Current selected texture surfaces (if any) */
- uint32_t aSidActiveTexture[SVGA3D_MAX_TEXTURE_STAGE];
- /* Per context pixel and vertex shaders. */
- uint32_t cPixelShaders;
- PVMSVGA3DSHADER paPixelShader;
- uint32_t cVertexShaders;
- PVMSVGA3DSHADER paVertexShader;
- /* Keep track of the internal state to be able to recreate the context properly (save/restore, window resize). */
- struct
- {
- uint32_t u32UpdateFlags;
-
- SVGA3dRenderState aRenderState[SVGA3D_RS_MAX];
- SVGA3dTextureState aTextureState[SVGA3D_MAX_TEXTURE_STAGE][SVGA3D_TS_MAX];
- VMSVGATRANSFORMSTATE aTransformState[SVGA3D_TRANSFORM_MAX];
- VMSVGAMATERIALSTATE aMaterial[SVGA3D_FACE_MAX];
- VMSVGACLIPPLANESTATE aClipPlane[SVGA3D_CLIPPLANE_MAX];
- VMSVGALIGHTSTATE aLightData[SVGA3D_MAX_LIGHTS];
-
- uint32_t aRenderTargets[SVGA3D_RT_MAX];
- SVGA3dRect RectScissor;
- SVGA3dRect RectViewPort;
- SVGA3dZRange zRange;
- uint32_t shidPixel;
- uint32_t shidVertex;
-
- uint32_t cPixelShaderConst;
- PVMSVGASHADERCONST paPixelShaderConst;
- uint32_t cVertexShaderConst;
- PVMSVGASHADERCONST paVertexShaderConst;
- } state;
-} VMSVGA3DCONTEXT, *PVMSVGA3DCONTEXT;
-
-/**
- * SSM descriptor table for the VMSVGA3DCONTEXT structure.
- */
-static SSMFIELD const g_aVMSVGA3DCONTEXTFields[] =
-{
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, id),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, pDevice),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, hwnd),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, sidRenderTarget),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DCONTEXT, aSidActiveTexture),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cPixelShaders),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paPixelShader),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, cVertexShaders),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, paVertexShader),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.u32UpdateFlags),
-
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTextureState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aTransformState),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aMaterial),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aClipPlane),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aLightData),
-
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.aRenderTargets),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectScissor),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.RectViewPort),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.zRange),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidPixel),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.shidVertex),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cPixelShaderConst),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paPixelShaderConst),
- SSMFIELD_ENTRY( VMSVGA3DCONTEXT, state.cVertexShaderConst),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DCONTEXT, state.paVertexShaderConst),
- SSMFIELD_ENTRY_TERM()
-};
-typedef struct
-{
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
- IDirect3D9 *pD3D9;
-#else
- IDirect3D9Ex *pD3D9;
-#endif
- D3DCAPS9 caps;
-
- /** Window Thread. */
- R3PTRTYPE(RTTHREAD) pWindowThread;
- HMODULE hInstance;
- /** Window request semaphore. */
- RTSEMEVENT WndRequestSem;
-
- /** The size of papContexts. */
- uint32_t cContexts;
- /** The size of papSurfaces. */
- uint32_t cSurfaces;
- /** Contexts indexed by ID. Grown as needed. */
- PVMSVGA3DCONTEXT *papContexts;
- /** Surfaces indexed by ID. Grown as needed. */
- PVMSVGA3DSURFACE *papSurfaces;
-
- bool fSupportedSurfaceINTZ;
- bool fSupportedSurfaceNULL;
-} VMSVGA3DSTATE, *PVMSVGA3DSTATE;
-
-/**
- * SSM descriptor table for the VMSVGA3DSTATE structure.
- */
-static SSMFIELD const g_aVMSVGA3DSTATEFields[] =
-{
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, pD3D9),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, caps),
-
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, pWindowThread),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, hInstance),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, WndRequestSem),
-
- SSMFIELD_ENTRY( VMSVGA3DSTATE, cContexts),
- SSMFIELD_ENTRY( VMSVGA3DSTATE, cSurfaces),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, papContexts),
- SSMFIELD_ENTRY_IGN_HCPTR( VMSVGA3DSTATE, papSurfaces),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, fSupportedSurfaceINTZ),
- SSMFIELD_ENTRY_IGNORE( VMSVGA3DSTATE, fSupportedSurfaceNULL),
- SSMFIELD_ENTRY_TERM()
-};
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
typedef struct
{
@@ -383,7 +71,11 @@ typedef struct
SVGA3dFormatOp FormatOp;
} VMSVGA3DFORMATSUPPORT;
-VMSVGA3DFORMATSUPPORT aFormatSupport[] =
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static VMSVGA3DFORMATSUPPORT const g_aFormatSupport[] =
{
{
0,
@@ -442,7 +134,7 @@ VMSVGA3DFORMATSUPPORT aFormatSupport[] =
}
};
-VMSVGA3DFORMATSUPPORT aFeatureReject[] =
+static VMSVGA3DFORMATSUPPORT const g_aFeatureReject[] =
{
{
D3DUSAGE_QUERY_WRAPANDMIP,
@@ -461,20 +153,21 @@ VMSVGA3DFORMATSUPPORT aFeatureReject[] =
},
};
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
static void vmsvgaDumpD3DCaps(D3DCAPS9 *pCaps);
-static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext, PVMSVGA3DSURFACE pSurface);
-RT_C_DECLS_BEGIN
-RT_C_DECLS_END
+
int vmsvga3dInit(PVGASTATE pThis)
{
PVMSVGA3DSTATE pState;
int rc;
- pThis->svga.p3dState = RTMemAllocZ(sizeof(VMSVGA3DSTATE));
+ pThis->svga.p3dState = pState = (PVMSVGA3DSTATE)RTMemAllocZ(sizeof(VMSVGA3DSTATE));
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
- pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
/* Create event semaphore. */
rc = RTSemEventCreate(&pState->WndRequestSem);
@@ -497,14 +190,14 @@ int vmsvga3dInit(PVGASTATE pThis)
int vmsvga3dPowerOn(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
HRESULT hr;
if (pState->pD3D9)
return VINF_SUCCESS; /* already initialized (load state) */
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
+#ifdef VBOX_VMSVGA3D_WITH_WINE_OPENGL
pState->pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
AssertReturn(pState->pD3D9, VERR_INTERNAL_ERROR);
#else
@@ -590,7 +283,7 @@ int vmsvga3dPowerOn(PVGASTATE pThis)
int vmsvga3dReset(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
/* Destroy all leftover surfaces. */
@@ -611,7 +304,7 @@ int vmsvga3dReset(PVGASTATE pThis)
int vmsvga3dTerminate(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pThis->svga.p3dState, VERR_NO_MEMORY);
int rc = vmsvga3dReset(pThis);
@@ -629,10 +322,11 @@ int vmsvga3dTerminate(PVGASTATE pThis)
return VINF_SUCCESS;
}
-/* Shared functions that depend on private structure definitions. */
-#define VMSVGA3D_DIRECT3D
-#include "DevVGA-SVGA3d-shared.h"
-
+void vmsvga3dUpdateHostScreenViewport(PVGASTATE pThis, uint32_t idScreen, VMSVGAVIEWPORT const *pOldViewport)
+{
+ /** @todo Scroll the screen content without requiring the guest to redraw. */
+ NOREF(pThis); NOREF(idScreen); NOREF(pOldViewport);
+}
static uint32_t vmsvga3dGetSurfaceFormatSupport(PVMSVGA3DSTATE pState3D, uint32_t idx3dCaps, D3DFORMAT format)
{
@@ -648,35 +342,35 @@ static uint32_t vmsvga3dGetSurfaceFormatSupport(PVMSVGA3DSTATE pState3D, uint32_
D3DRTYPE_SURFACE,
format);
- for (unsigned i = 0; i < RT_ELEMENTS(aFormatSupport); i++)
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aFormatSupport); i++)
{
hr = pState3D->pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8, /* assume standard 32-bit display mode */
- aFormatSupport[i].Usage,
- aFormatSupport[i].ResourceType,
+ g_aFormatSupport[i].Usage,
+ g_aFormatSupport[i].ResourceType,
format);
if (hr == D3D_OK)
- result |= aFormatSupport[i].FormatOp;
+ result |= g_aFormatSupport[i].FormatOp;
}
/* Check for features only if the format is supported in any form. */
if (result)
{
- for (unsigned i = 0; i < RT_ELEMENTS(aFeatureReject); i++)
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aFeatureReject); i++)
{
hr = pState3D->pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
D3DFMT_X8R8G8B8, /* assume standard 32-bit display mode */
- aFeatureReject[i].Usage,
- aFeatureReject[i].ResourceType,
+ g_aFeatureReject[i].Usage,
+ g_aFeatureReject[i].ResourceType,
format);
if (hr != D3D_OK)
- result |= aFeatureReject[i].FormatOp;
+ result |= g_aFeatureReject[i].FormatOp;
}
}
- /* @todo missing:
+ /** @todo missing:
*
* SVGA3DFORMAT_OP_PIXELSIZE
*/
@@ -730,7 +424,7 @@ static uint32_t vmsvga3dGetDepthFormatSupport(PVMSVGA3DSTATE pState3D, uint32_t
int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
D3DCAPS9 *pCaps = &pState->caps;
int rc = VINF_SUCCESS;
@@ -1231,7 +925,7 @@ int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val)
/**
* Convert SVGA format value to its D3D equivalent
*/
-static D3DFORMAT vmsvga3dSurfaceFormat2D3D(SVGA3dSurfaceFormat format)
+D3DFORMAT vmsvga3dSurfaceFormat2D3D(SVGA3dSurfaceFormat format)
{
switch (format)
{
@@ -1383,215 +1077,69 @@ D3DMULTISAMPLE_TYPE vmsvga3dMultipeSampleCount2D3D(uint32_t multisampleCount)
return (D3DMULTISAMPLE_TYPE)multisampleCount;
}
-int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format, SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES],
- uint32_t multisampleCount, SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *pMipLevelSize)
-{
- PVMSVGA3DSURFACE pSurface;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- AssertReturn(pState, VERR_NO_MEMORY);
-
- Log(("vmsvga3dSurfaceDefine: sid=%x surfaceFlags=%x format=%s (%x) multiSampleCount=%d autogenFilter=%d, cMipLevels=%d size=(%d,%d,%d)\n",
- sid, surfaceFlags, vmsvgaSurfaceType2String(format), format, multisampleCount, autogenFilter, cMipLevels, pMipLevelSize->width, pMipLevelSize->height, pMipLevelSize->depth));
-
- AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(cMipLevels >= 1, VERR_INVALID_PARAMETER);
- /* Assuming all faces have the same nr of mipmaps. */
- AssertReturn(!(surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels * 6, VERR_INVALID_PARAMETER);
- AssertReturn((surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels, VERR_INVALID_PARAMETER);
-
- if (sid >= pState->cSurfaces)
- {
- /* Grow the array. */
- uint32_t cNew = RT_ALIGN(sid + 15, 16);
- void *pvNew = RTMemRealloc(pState->papSurfaces, sizeof(pState->papSurfaces[0]) * cNew);
- AssertReturn(pvNew, VERR_NO_MEMORY);
- pState->papSurfaces = (PVMSVGA3DSURFACE *)pvNew;
- while (pState->cSurfaces < cNew)
- {
- pSurface = (PVMSVGA3DSURFACE)RTMemAllocZ(sizeof(*pSurface));
- AssertReturn(pSurface, VERR_NO_MEMORY);
- pSurface->id = SVGA3D_INVALID_ID;
- pState->papSurfaces[pState->cSurfaces++] = pSurface;
- }
- }
- pSurface = pState->papSurfaces[sid];
-
- /* If one already exists with this id, then destroy it now. */
- if (pSurface->id != SVGA3D_INVALID_ID)
- vmsvga3dSurfaceDestroy(pThis, sid);
-
- memset(pSurface, 0, sizeof(*pSurface));
- pSurface->id = sid;
- pSurface->idAssociatedContext = SVGA3D_INVALID_ID;
- pSurface->hSharedObject = NULL;
- pSurface->pSharedObjectTree = NULL;
-
- /* The surface type is sort of undefined now, even though the hints and format can help to clear that up.
- * In some case we'll have to wait until the surface is used to create the D3D object.
- */
- switch (format)
- {
- case SVGA3D_Z_D32:
- case SVGA3D_Z_D16:
- case SVGA3D_Z_D24S8:
- case SVGA3D_Z_D15S1:
- case SVGA3D_Z_D24X8:
- case SVGA3D_Z_DF16:
- case SVGA3D_Z_DF24:
- case SVGA3D_Z_D24S8_INT:
- surfaceFlags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
- break;
-
- /* Texture compression formats */
- case SVGA3D_DXT1:
- case SVGA3D_DXT2:
- case SVGA3D_DXT3:
- case SVGA3D_DXT4:
- case SVGA3D_DXT5:
- /* Bump-map formats */
- case SVGA3D_BUMPU8V8:
- case SVGA3D_BUMPL6V5U5:
- case SVGA3D_BUMPX8L8V8U8:
- case SVGA3D_BUMPL8V8U8:
- case SVGA3D_V8U8:
- case SVGA3D_Q8W8V8U8:
- case SVGA3D_CxV8U8:
- case SVGA3D_X8L8V8U8:
- case SVGA3D_A2W10V10U10:
- case SVGA3D_V16U16:
- /* Typical render target formats; we should allow render target buffers to be used as textures. */
- case SVGA3D_X8R8G8B8:
- case SVGA3D_A8R8G8B8:
- case SVGA3D_R5G6B5:
- case SVGA3D_X1R5G5B5:
- case SVGA3D_A1R5G5B5:
- case SVGA3D_A4R4G4B4:
- surfaceFlags |= SVGA3D_SURFACE_HINT_TEXTURE;
- break;
-
- case SVGA3D_LUMINANCE8:
- case SVGA3D_LUMINANCE4_ALPHA4:
- case SVGA3D_LUMINANCE16:
- case SVGA3D_LUMINANCE8_ALPHA8:
- case SVGA3D_ARGB_S10E5: /* 16-bit floating-point ARGB */
- case SVGA3D_ARGB_S23E8: /* 32-bit floating-point ARGB */
- case SVGA3D_A2R10G10B10:
- case SVGA3D_ALPHA8:
- case SVGA3D_R_S10E5:
- case SVGA3D_R_S23E8:
- case SVGA3D_RG_S10E5:
- case SVGA3D_RG_S23E8:
- case SVGA3D_G16R16:
- case SVGA3D_A16B16G16R16:
- case SVGA3D_UYVY:
- case SVGA3D_YUY2:
- case SVGA3D_NV12:
- case SVGA3D_AYUV:
- case SVGA3D_BC4_UNORM:
- case SVGA3D_BC5_UNORM:
- break;
- /*
- * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
- * the most efficient format to use when creating new surfaces
- * expressly for index or vertex data.
- */
- case SVGA3D_BUFFER:
- break;
- }
+/**
+ * Destroy backend specific surface bits (part of SVGA_3D_CMD_SURFACE_DESTROY).
+ *
+ * @param pState The VMSVGA3d state.
+ * @param pSurface The surface being destroyed.
+ */
+void vmsvga3dBackSurfaceDestroy(PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface)
+{
+ RTAvlU32Destroy(&pSurface->pSharedObjectTree, vmsvga3dSharedSurfaceDestroyTree, pSurface);
+ Assert(pSurface->pSharedObjectTree == NULL);
- pSurface->flags = surfaceFlags;
- pSurface->format = format;
- memcpy(pSurface->faces, face, sizeof(face));
- pSurface->cFaces = 1; /* check for cube maps later */
- pSurface->multiSampleCount = multisampleCount;
- pSurface->autogenFilter = autogenFilter;
- Assert(autogenFilter != SVGA3D_TEX_FILTER_FLATCUBIC);
- Assert(autogenFilter != SVGA3D_TEX_FILTER_GAUSSIANCUBIC);
- pSurface->pMipmapLevels = (PVMSVGA3DMIPMAPLEVEL)RTMemAllocZ(cMipLevels * sizeof(VMSVGA3DMIPMAPLEVEL));
- AssertReturn(pSurface->pMipmapLevels, VERR_NO_MEMORY);
-
- for (uint32_t i=0; i < cMipLevels; i++)
- pSurface->pMipmapLevels[i].size = pMipLevelSize[i];
-
- /* Translate the format and usage flags to D3D. */
- pSurface->formatD3D = vmsvga3dSurfaceFormat2D3D(format);
- pSurface->cbBlock = vmsvga3dSurfaceFormatSize(format);
- pSurface->multiSampleTypeD3D= vmsvga3dMultipeSampleCount2D3D(multisampleCount);
- pSurface->fUsageD3D = 0;
- if (surfaceFlags & SVGA3D_SURFACE_HINT_DYNAMIC)
- pSurface->fUsageD3D |= D3DUSAGE_DYNAMIC;
- if (surfaceFlags & SVGA3D_SURFACE_HINT_RENDERTARGET)
- pSurface->fUsageD3D |= D3DUSAGE_RENDERTARGET;
- if (surfaceFlags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL)
- pSurface->fUsageD3D |= D3DUSAGE_DEPTHSTENCIL;
- if (surfaceFlags & SVGA3D_SURFACE_HINT_WRITEONLY)
- pSurface->fUsageD3D |= D3DUSAGE_WRITEONLY;
- if (surfaceFlags & SVGA3D_SURFACE_AUTOGENMIPMAPS)
- pSurface->fUsageD3D |= D3DUSAGE_AUTOGENMIPMAP;
-
- switch (surfaceFlags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
+ switch (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)
{
case SVGA3D_SURFACE_CUBEMAP:
- Log(("SVGA3D_SURFACE_CUBEMAP\n"));
- pSurface->cFaces = 6;
+ AssertFailed(); /** @todo */
break;
case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- Log(("SVGA3D_SURFACE_HINT_INDEXBUFFER\n"));
- /* else type unknown at this time; postpone buffer creation */
+ if (pSurface->u.pIndexBuffer)
+ pSurface->u.pIndexBuffer->Release();
break;
case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- Log(("SVGA3D_SURFACE_HINT_VERTEXBUFFER\n"));
- /* Type unknown at this time; postpone buffer creation */
+ if (pSurface->u.pVertexBuffer)
+ pSurface->u.pVertexBuffer->Release();
break;
case SVGA3D_SURFACE_HINT_TEXTURE:
- Log(("SVGA3D_SURFACE_HINT_TEXTURE\n"));
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ if (pSurface->u.pTexture)
+ pSurface->u.pTexture->Release();
+ if (pSurface->bounce.pTexture)
+ pSurface->bounce.pTexture->Release();
break;
case SVGA3D_SURFACE_HINT_RENDERTARGET:
- Log(("SVGA3D_SURFACE_HINT_RENDERTARGET\n"));
- break;
-
case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- Log(("SVGA3D_SURFACE_HINT_DEPTHSTENCIL\n"));
+ case SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_HINT_TEXTURE: /** @todo actual texture surface not supported */
+ if (pSurface->fStencilAsTexture)
+ pSurface->u.pTexture->Release();
+ else
+ if (pSurface->u.pSurface)
+ pSurface->u.pSurface->Release();
break;
default:
- /* Unknown; decide later. */
+ AssertMsg(!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface), ("type=%x\n", (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)));
break;
}
- Assert(!pSurface->u.pSurface);
-
- /* Allocate buffer to hold the surface data until we can move it into a D3D object */
- for (uint32_t iFace=0; iFace < pSurface->cFaces; iFace++)
- {
- for (uint32_t i=0; i < pSurface->faces[iFace].numMipLevels; i++)
- {
- uint32_t idx = i + iFace * pSurface->faces[0].numMipLevels;
-
- Log(("vmsvga3dSurfaceDefine: face %d mip level %d (%d,%d,%d)\n", iFace, i, pSurface->pMipmapLevels[idx].size.width, pSurface->pMipmapLevels[idx].size.height, pSurface->pMipmapLevels[idx].size.depth));
- Log(("vmsvga3dSurfaceDefine: cbPitch=%x cbBlock=%x \n", pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width, pSurface->cbBlock));
-
- pSurface->pMipmapLevels[idx].cbSurfacePitch = pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width;
- pSurface->pMipmapLevels[idx].cbSurface = pSurface->pMipmapLevels[idx].cbSurfacePitch * pSurface->pMipmapLevels[idx].size.height * pSurface->pMipmapLevels[idx].size.depth;
- pSurface->pMipmapLevels[idx].pSurfaceData = RTMemAllocZ(pSurface->pMipmapLevels[idx].cbSurface);
- AssertReturn(pSurface->pMipmapLevels[idx].pSurfaceData, VERR_NO_MEMORY);
- }
- }
- return VINF_SUCCESS;
+ if (pSurface->pQuery)
+ pSurface->pQuery->Release();
}
+
/*
* Release all shared surface objects.
*/
-static int vmsvga3dSharedSurfaceDestroyTree(PAVLU32NODECORE pNode, void *pParam)
+DECLCALLBACK(int) vmsvga3dSharedSurfaceDestroyTree(PAVLU32NODECORE pNode, void *pvParam)
{
PVMSVGA3DSHAREDSURFACE pSharedSurface = (PVMSVGA3DSHAREDSURFACE)pNode;
- PVMSVGA3DSURFACE pSurface = (PVMSVGA3DSURFACE)pParam;
+ PVMSVGA3DSURFACE pSurface = (PVMSVGA3DSURFACE)pvParam;
switch (pSurface->flags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
{
@@ -1611,103 +1159,6 @@ static int vmsvga3dSharedSurfaceDestroyTree(PAVLU32NODECORE pNode, void *pParam)
return 0;
}
-int vmsvga3dSurfaceDestroy(PVGASTATE pThis, uint32_t sid)
-{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- AssertReturn(pState, VERR_NO_MEMORY);
-
- if ( sid < pState->cSurfaces
- && pState->papSurfaces[sid]->id == sid)
- {
- PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
-
- Log(("vmsvga3dSurfaceDestroy id %x\n", sid));
-
- /* Check all contexts if this surface is used as a render target or active texture. */
- for (uint32_t cid = 0; cid < pState->cContexts; cid++)
- {
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
- if (pContext->id == cid)
- {
- for (uint32_t i = 0; i < RT_ELEMENTS(pContext->aSidActiveTexture); i++)
- {
- if (pContext->aSidActiveTexture[i] == sid)
- pContext->aSidActiveTexture[i] = SVGA3D_INVALID_ID;
- }
- if (pContext->sidRenderTarget == sid)
- pContext->sidRenderTarget = SVGA3D_INVALID_ID;
- }
- }
-
- RTAvlU32Destroy(&pSurface->pSharedObjectTree, vmsvga3dSharedSurfaceDestroyTree, pSurface);
- Assert(pSurface->pSharedObjectTree == NULL);
-
- switch (pSurface->flags & ( SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER
- | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET
- | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
- {
- case SVGA3D_SURFACE_CUBEMAP:
- AssertFailed(); /* @todo */
- break;
-
- case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- if (pSurface->u.pIndexBuffer)
- pSurface->u.pIndexBuffer->Release();
- break;
-
- case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- if (pSurface->u.pVertexBuffer)
- pSurface->u.pVertexBuffer->Release();
- break;
-
- case SVGA3D_SURFACE_HINT_TEXTURE:
- case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
- if (pSurface->u.pTexture)
- pSurface->u.pTexture->Release();
- if (pSurface->bounce.pTexture)
- pSurface->bounce.pTexture->Release();
- break;
-
- case SVGA3D_SURFACE_HINT_RENDERTARGET:
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_HINT_TEXTURE: /* @todo actual texture surface not supported */
- if (pSurface->fStencilAsTexture)
- pSurface->u.pTexture->Release();
- else
- if (pSurface->u.pSurface)
- pSurface->u.pSurface->Release();
- break;
-
- default:
- AssertMsg(!pSurface->u.pSurface, ("type=%x\n", (pSurface->flags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))));
- break;
- }
-
- if (pSurface->pMipmapLevels)
- {
- for (uint32_t face=0; face < pSurface->cFaces; face++)
- {
- for (uint32_t i=0; i < pSurface->faces[face].numMipLevels; i++)
- {
- uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
- if (pSurface->pMipmapLevels[idx].pSurfaceData)
- RTMemFree(pSurface->pMipmapLevels[idx].pSurfaceData);
- }
- }
- RTMemFree(pSurface->pMipmapLevels);
- }
- if (pSurface->pQuery)
- pSurface->pQuery->Release();
-
- memset(pSurface, 0, sizeof(*pSurface));
- pSurface->id = SVGA3D_INVALID_ID;
- }
- else
- AssertFailedReturn(VERR_INVALID_PARAMETER);
-
- return VINF_SUCCESS;
-}
-
/* Get the shared surface copy or create a new one. */
static PVMSVGA3DSHAREDSURFACE vmsvga3dSurfaceGetSharedCopy(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface)
{
@@ -1747,27 +1198,19 @@ static PVMSVGA3DSHAREDSURFACE vmsvga3dSurfaceGetSharedCopy(PVGASTATE pThis, PVMS
return pSharedSurface;
}
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
-#define vmsvga3dSurfaceTrackUsage(a, b, c)
-#define vmsvga3dSurfaceFlush(a, b)
-#else
/* Inject a query event into the D3D pipeline so we can check when usage of this surface has finished.
* (D3D does not synchronize shared surface usage)
*/
-static int vmsvga3dSurfaceTrackUsage(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t sid)
+static int vmsvga3dSurfaceTrackUsage(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, PVMSVGA3DSURFACE pSurface)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
- HRESULT hr;
-
- AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sid < pState->cSurfaces && pState->papSurfaces[sid]->id == sid, VERR_INVALID_PARAMETER);
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
+ Assert(pSurface->id != SVGA3D_INVALID_ID);
/* Nothing to do if this surface hasn't been shared. */
if (pSurface->pSharedObjectTree == NULL)
return VINF_SUCCESS;
- Log(("vmsvga3dSurfaceTrackUsage: track usage of surface id=%x (cid=%x)\n", sid, pContext->id));
+ Log(("vmsvga3dSurfaceTrackUsage: track usage of surface id=%x (cid=%x)\n", pSurface->id, pContext->id));
/* Release the previous query object. */
if (pSurface->pQuery)
@@ -1776,19 +1219,40 @@ static int vmsvga3dSurfaceTrackUsage(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext,
pSurface->pQuery->Release();
pSurface->pQuery = NULL;
}
- hr = pContext->pDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSurface->pQuery);
+ HRESULT hr = pContext->pDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSurface->pQuery);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceTrackUsage: CreateQuery failed with %x\n", hr), VERR_INTERNAL_ERROR);
hr = pSurface->pQuery->Issue(D3DISSUE_END);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceTrackUsage: Issue failed with %x\n", hr), VERR_INTERNAL_ERROR);
+#endif /* !VBOX_VMSVGA3D_WITH_WINE_OPENGL */
return VINF_SUCCESS;
}
+/**
+ * Surface ID based version of vmsvga3dSurfaceTrackUsage.
+ *
+ * @returns VBox status code.
+ * @param pState The VMSVGA3d state.
+ * @param pContext The context.
+ * @param sid The surface ID.
+ */
+static int vmsvga3dSurfaceTrackUsageById(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t sid)
+{
+ Assert(sid < SVGA3D_MAX_SURFACE_IDS);
+ AssertReturn(sid < pState->cSurfaces, VERR_INVALID_PARAMETER);
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ AssertReturn(pSurface && pSurface->id == sid, VERR_INVALID_PARAMETER);
+
+ return vmsvga3dSurfaceTrackUsage(pState, pContext, pSurface);
+}
+
+
/* Wait for all drawing, that uses this surface, to finish. */
-static int vmsvga3dSurfaceFlush(PVGASTATE pThis, PVMSVGA3DSURFACE pSurface)
+int vmsvga3dSurfaceFlush(PVGASTATE pThis, PVMSVGA3DSURFACE pSurface)
{
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
HRESULT hr;
if (!pSurface->pQuery)
@@ -1810,14 +1274,15 @@ static int vmsvga3dSurfaceFlush(PVGASTATE pThis, PVMSVGA3DSURFACE pSurface)
pSurface->pQuery->Release();
pSurface->pQuery = NULL;
+#endif /* !VBOX_VMSVGA3D_WITH_WINE_OPENGL */
return VINF_SUCCESS;
}
-#endif /* VBOX_VMSVGA3D_WITH_OPENGL */
-int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfaceImageId src, uint32_t cCopyBoxes, SVGA3dCopyBox *pBox)
+int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfaceImageId src,
+ uint32_t cCopyBoxes, SVGA3dCopyBox *pBox)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pSurfaceSrc;
uint32_t sidSrc = src.sid;
PVMSVGA3DSURFACE pSurfaceDest;
@@ -1859,7 +1324,7 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
pContext = pState->papContexts[cid];
Log(("vmsvga3dSurfaceCopy: create texture surface id=%x type=%d format=%d -> create texture\n", sidDest, pSurfaceDest->flags, pSurfaceDest->format));
- rc = vmsvga3dCreateTexture(pContext, cid, pSurfaceDest);
+ rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pSurfaceDest);
AssertRCReturn(rc, rc);
}
@@ -1884,7 +1349,7 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
vmsvga3dSurfaceFlush(pThis, pSurfaceSrc);
vmsvga3dSurfaceFlush(pThis, pSurfaceDest);
-#ifndef VBOX_VMSVGA3D_WITH_OPENGL
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
if ( fSrcTexture
&& pSurfaceSrc->idAssociatedContext != cid)
{
@@ -1954,8 +1419,8 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
pSrc->Release();
/* Track the StretchRect operation. */
- vmsvga3dSurfaceTrackUsage(pThis, pContext, sidSrc);
- vmsvga3dSurfaceTrackUsage(pThis, pContext, sidDest);
+ vmsvga3dSurfaceTrackUsage(pState, pContext, pSurfaceSrc);
+ vmsvga3dSurfaceTrackUsage(pState, pContext, pSurfaceDest);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceCopy: UpdateSurface failed with %x\n", hr), VERR_INTERNAL_ERROR);
}
@@ -2060,8 +1525,20 @@ int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfac
return VINF_SUCCESS;
}
-/* Create D3D texture object for the specified surface. */
-static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext, PVMSVGA3DSURFACE pSurface)
+
+/**
+ * Create D3D/OpenGL texture object for the specified surface.
+ *
+ * Surfaces are created when needed.
+ *
+ * @param pState The VMSVGA3d state.
+ * @param pContext The context.
+ * @param idAssociatedContext Probably the same as pContext->id.
+ * @param pSurface The surface to create the texture for.
+ */
+int vmsvga3dBackCreateTexture(PVMSVGA3DSTATE pState, PVMSVGA3DCONTEXT pContext, uint32_t idAssociatedContext,
+ PVMSVGA3DSURFACE pSurface)
+
{
HRESULT hr;
IDirect3DTexture9 *pTexture;
@@ -2081,7 +1558,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
D3DPOOL_DEFAULT,
&pSurface->u.pTexture,
&pSurface->hSharedObject /* might result in poor performance */);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: CreateTexture INTZ failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: CreateTexture INTZ failed with %x\n", hr), VERR_INTERNAL_ERROR);
pTexture = pSurface->u.pTexture;
pSurface->fStencilAsTexture = true;
@@ -2107,7 +1584,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
D3DPOOL_SYSTEMMEM,
&pSurface->bounce.pTexture,
NULL);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: CreateTexture (systemmem) failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: CreateTexture (systemmem) failed with %x\n", hr), VERR_INTERNAL_ERROR);
pTexture = pSurface->bounce.pTexture;
}
else
@@ -2122,7 +1599,7 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
D3DPOOL_DEFAULT,
&pSurface->u.pTexture,
&pSurface->hSharedObject /* might result in poor performance */);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: CreateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: CreateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
pTexture = pSurface->u.pTexture;
}
}
@@ -2131,12 +1608,12 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
{
/* Set the mip map generation filter settings. */
hr = pSurface->u.pTexture->SetAutoGenFilterType((D3DTEXTUREFILTERTYPE)pSurface->autogenFilter);
- AssertMsg(hr == D3D_OK, ("vmsvga3dCreateTexture: SetAutoGenFilterType failed with %x\n", hr));
+ AssertMsg(hr == D3D_OK, ("vmsvga3dBackCreateTexture: SetAutoGenFilterType failed with %x\n", hr));
}
if (pSurface->fDirty)
{
- Log(("vmsvga3dCreateTexture: sync dirty texture\n"));
+ Log(("vmsvga3dBackCreateTexture: sync dirty texture\n"));
for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
{
if (pSurface->pMipmapLevels[i].fDirty)
@@ -2148,9 +1625,9 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
NULL, /* entire texture */
0);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
- Log(("vmsvga3dCreateTexture: sync dirty texture mipmap level %d (pitch %x vs %x)\n", i, LockedRect.Pitch, pSurface->pMipmapLevels[i].cbSurfacePitch));
+ Log(("vmsvga3dBackCreateTexture: sync dirty texture mipmap level %d (pitch %x vs %x)\n", i, LockedRect.Pitch, pSurface->pMipmapLevels[i].cbSurfacePitch));
uint8_t *pDest = (uint8_t *)LockedRect.pBits;
uint8_t *pSrc = (uint8_t *)pSurface->pMipmapLevels[i].pSurfaceData;
@@ -2163,17 +1640,17 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
}
hr = pTexture->UnlockRect(i /* texture level */);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
pSurface->pMipmapLevels[i].fDirty = false;
}
}
if (pSurface->bounce.pTexture)
{
- Log(("vmsvga3dCreateTexture: sync dirty texture from bounce buffer\n"));
+ Log(("vmsvga3dBackCreateTexture: sync dirty texture from bounce buffer\n"));
hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->u.pTexture);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dCreateTexture: UpdateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dBackCreateTexture: UpdateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
/* We will now use the bounce texture for all memory accesses, so free our surface memory buffer. */
for (uint32_t i = 0; i < pSurface->faces[0].numMipLevels; i++)
@@ -2189,103 +1666,69 @@ static int vmsvga3dCreateTexture(PVMSVGA3DCONTEXT pContext, uint32_t idAssociate
return VINF_SUCCESS;
}
-int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dBox destBox, SVGA3dSurfaceImageId src, SVGA3dBox srcBox, SVGA3dStretchBltMode mode)
-{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- PVMSVGA3DSURFACE pSurfaceSrc;
- uint32_t sidSrc = src.sid;
- PVMSVGA3DSURFACE pSurfaceDest;
- uint32_t sidDest = dest.sid;
- int rc = VINF_SUCCESS;
- uint32_t cid;
- PVMSVGA3DCONTEXT pContext;
-
- AssertReturn(pState, VERR_NO_MEMORY);
- AssertReturn(sidSrc < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sidSrc < pState->cSurfaces && pState->papSurfaces[sidSrc]->id == sidSrc, VERR_INVALID_PARAMETER);
- AssertReturn(sidDest < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sidDest < pState->cSurfaces && pState->papSurfaces[sidDest]->id == sidDest, VERR_INVALID_PARAMETER);
-
- pSurfaceSrc = pState->papSurfaces[sidSrc];
- pSurfaceDest = pState->papSurfaces[sidDest];
- AssertReturn(pSurfaceSrc->faces[0].numMipLevels > src.mipmap, VERR_INVALID_PARAMETER);
- AssertReturn(pSurfaceDest->faces[0].numMipLevels > dest.mipmap, VERR_INVALID_PARAMETER);
-
- Log(("vmsvga3dSurfaceStretchBlt: src sid=%x (%d,%d)(%d,%d) dest sid=%x (%d,%d)(%d,%d) mode=%x\n", src.sid, srcBox.x, srcBox.y, srcBox.x + srcBox.w, srcBox.y + srcBox.h, dest.sid, destBox.x, destBox.y, destBox.x + destBox.w, destBox.y + destBox.h, mode));
- /* @todo stricter checks for associated context */
- cid = pSurfaceDest->idAssociatedContext;
- if (cid == SVGA3D_INVALID_ID)
- cid = pSurfaceSrc->idAssociatedContext;
-
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSurfaceStretchBlt invalid context id!\n"));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- pContext = pState->papContexts[cid];
-
- if (!pSurfaceSrc->u.pSurface)
- {
- /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
- Log(("vmsvga3dSurfaceStretchBlt: unknown src surface id=%x type=%d format=%d -> create texture\n", sidSrc, pSurfaceSrc->flags, pSurfaceSrc->format));
- rc = vmsvga3dCreateTexture(pContext, cid, pSurfaceSrc);
- AssertRCReturn(rc, rc);
- }
-
- if (!pSurfaceDest->u.pSurface)
- {
- /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
- Log(("vmsvga3dSurfaceStretchBlt: unknown dest surface id=%x type=%d format=%d -> create texture\n", sidDest, pSurfaceDest->flags, pSurfaceDest->format));
- rc = vmsvga3dCreateTexture(pContext, cid, pSurfaceDest);
- AssertRCReturn(rc, rc);
- }
+/**
+ * Backend worker for implementing SVGA_3D_CMD_SURFACE_STRETCHBLT.
+ *
+ * @returns VBox status code.
+ * @param pThis The VGA device instance.
+ * @param pState The VMSVGA3d state.
+ * @param pDstSurface The destination host surface.
+ * @param uDstMipmap The destination mipmap level (valid).
+ * @param pDstBox The destination box.
+ * @param pSrcSurface The source host surface.
+ * @param uSrcMipmap The source mimap level (valid).
+ * @param pSrcBox The source box.
+ * @param enmMode The strecht blt mode .
+ * @param pContext The VMSVGA3d context (already current for OGL).
+ */
+int vmsvga3dBackSurfaceStretchBlt(PVGASTATE pThis, PVMSVGA3DSTATE pState,
+ PVMSVGA3DSURFACE pDstSurface, uint32_t uDstMipmap, SVGA3dBox const *pDstBox,
+ PVMSVGA3DSURFACE pSrcSurface, uint32_t uSrcMipmap, SVGA3dBox const *pSrcBox,
+ SVGA3dStretchBltMode enmMode, PVMSVGA3DCONTEXT pContext)
+{
+ HRESULT hr;
/* Flush the drawing pipeline for this surface as it could be used in a shared context. */
- vmsvga3dSurfaceFlush(pThis, pSurfaceSrc);
- vmsvga3dSurfaceFlush(pThis, pSurfaceDest);
-
- bool fSrcTexture = !!(pSurfaceSrc->flags & SVGA3D_SURFACE_HINT_TEXTURE);
- bool fDestTexture = !!(pSurfaceDest->flags & SVGA3D_SURFACE_HINT_TEXTURE);
-
- HRESULT hr;
- RECT RectSrc;
- RECT RectDest;
- D3DTEXTUREFILTERTYPE moded3d;
- IDirect3DSurface9 *pSrc;
- IDirect3DSurface9 *pDest;
-
- RectSrc.left = srcBox.x;
- RectSrc.top = srcBox.y;
- RectSrc.right = srcBox.x + srcBox.w; /* exclusive */
- RectSrc.bottom = srcBox.y + srcBox.h; /* exclusive */
- RectDest.left = destBox.x;
- RectDest.top = destBox.y;
- RectDest.right = destBox.x + destBox.w; /* exclusive */
- RectDest.bottom = destBox.y + destBox.h; /* exclusive */
-
- Assert(!destBox.z && !srcBox.z);
-
+ vmsvga3dSurfaceFlush(pThis, pSrcSurface);
+ vmsvga3dSurfaceFlush(pThis, pDstSurface);
+
+ RECT RectSrc;
+ RectSrc.left = pSrcBox->x;
+ RectSrc.top = pSrcBox->y;
+ RectSrc.right = pSrcBox->x + pSrcBox->w; /* exclusive */
+ RectSrc.bottom = pSrcBox->y + pSrcBox->h; /* exclusive */
+ Assert(!pSrcBox->z);
+
+ RECT RectDst;
+ RectDst.left = pDstBox->x;
+ RectDst.top = pDstBox->y;
+ RectDst.right = pDstBox->x + pDstBox->w; /* exclusive */
+ RectDst.bottom = pDstBox->y + pDstBox->h; /* exclusive */
+ Assert(!pDstBox->z);
+
+ IDirect3DSurface9 *pSrc;
+ bool const fSrcTexture = !!(pSrcSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE);
if (fSrcTexture)
{
- hr = pSurfaceSrc->u.pTexture->GetSurfaceLevel(src.mipmap /* Texture level */,
- &pSrc);
+ hr = pSrcSurface->u.pTexture->GetSurfaceLevel(uSrcMipmap /* Texture level */, &pSrc);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceStretchBlt: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
}
else
- pSrc = pSurfaceSrc->u.pSurface;
+ pSrc = pSrcSurface->u.pSurface;
- if (fDestTexture)
+ IDirect3DSurface9 *pDst;
+ bool const fDstTexture = !!(pDstSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE);
+ if (fDstTexture)
{
- hr = pSurfaceDest->u.pTexture->GetSurfaceLevel(dest.mipmap /* Texture level */,
- &pDest);
+ hr = pDstSurface->u.pTexture->GetSurfaceLevel(uDstMipmap /* Texture level */, &pDst);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceStretchBlt: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
}
else
- pDest = pSurfaceDest->u.pSurface;
+ pDst = pDstSurface->u.pSurface;
- switch (mode)
+ D3DTEXTUREFILTERTYPE moded3d;
+ switch (enmMode)
{
case SVGA3D_STRETCH_BLT_POINT:
moded3d = D3DTEXF_POINT;
@@ -2301,317 +1744,231 @@ int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3d
break;
}
- hr = pContext->pDevice->StretchRect(pSrc, &RectSrc, pDest, &RectDest, moded3d);
+ hr = pContext->pDevice->StretchRect(pSrc, &RectSrc, pDst, &RectDst, moded3d);
/* GetSurfaceLevel increases the reference count; release the objects again. */
- if (fDestTexture)
- pDest->Release();
+ if (fDstTexture)
+ pDst->Release();
if (fSrcTexture)
pSrc->Release();
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceStretchBlt: StretchRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
/* Track the StretchRect operation. */
- vmsvga3dSurfaceTrackUsage(pThis, pContext, sidSrc);
- vmsvga3dSurfaceTrackUsage(pThis, pContext, sidDest);
+ vmsvga3dSurfaceTrackUsage(pState, pContext, pSrcSurface);
+ vmsvga3dSurfaceTrackUsage(pState, pContext, pDstSurface);
return VINF_SUCCESS;
}
-int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
- uint32_t cCopyBoxes, SVGA3dCopyBox *pBoxes)
-{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
- PVMSVGA3DSURFACE pSurface;
- PVMSVGA3DMIPMAPLEVEL pMipLevel;
- uint32_t sid = host.sid;
- int rc = VINF_SUCCESS;
- AssertReturn(pState, VERR_NO_MEMORY);
- AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
- AssertReturn(sid < pState->cSurfaces && pState->papSurfaces[sid]->id == sid, VERR_INVALID_PARAMETER);
-
- pSurface = pState->papSurfaces[sid];
- AssertReturn(pSurface->faces[0].numMipLevels > host.mipmap, VERR_INVALID_PARAMETER);
- pMipLevel = &pSurface->pMipmapLevels[host.mipmap];
-
- if (pSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE)
- Log(("vmsvga3dSurfaceDMA TEXTURE guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
- else
- Log(("vmsvga3dSurfaceDMA guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
-
- if (!pSurface->u.pSurface)
+/**
+ * Backend worker for implementing SVGA_3D_CMD_SURFACE_DMA that copies one box.
+ *
+ * @returns Failure status code or @a rc.
+ * @param pThis The VGA device instance data.
+ * @param pState The VMSVGA3d state.
+ * @param pSurface The host surface.
+ * @param uHostMipmap The host mipmap level (valid).
+ * @param GuestPtr The guest pointer.
+ * @param cbSrcPitch The guest (?) pitch.
+ * @param transfer The transfer direction.
+ * @param pBox The box to copy.
+ * @param pContext The context (for OpenGL).
+ * @param rc The current rc for all boxes.
+ * @param iBox The current box number (for Direct 3D).
+ */
+int vmsvga3dBackSurfaceDMACopyBox(PVGASTATE pThis, PVMSVGA3DSTATE pState, PVMSVGA3DSURFACE pSurface, uint32_t uHostMipmap,
+ SVGAGuestPtr GuestPtr, uint32_t cbSrcPitch, SVGA3dTransferType transfer,
+ SVGA3dCopyBox const *pBox, PVMSVGA3DCONTEXT pContext, int rc, int iBox)
+{
+ HRESULT hr = D3D_OK;
+ DWORD dwFlags = transfer == SVGA3D_READ_HOST_VRAM ? D3DLOCK_READONLY : 0;
+ bool fTexture = false;
+ bool fVertex = false;
+ bool fRenderTargetTexture = false;
+ switch (pSurface->flags & VMSVGA3D_SURFACE_HINT_SWITCH_MASK)
{
- AssertReturn(pSurface->pMipmapLevels[host.mipmap].pSurfaceData, VERR_INTERNAL_ERROR);
-
- for (unsigned i = 0; i < cCopyBoxes; i++)
- {
- unsigned uDestOffset;
- unsigned cbSrcPitch;
-
- Log(("Copy box %d (%d,%d,%d)(%d,%d,%d)\n", i, pBoxes[i].srcx, pBoxes[i].srcy, pBoxes[i].srcz, pBoxes[i].w, pBoxes[i].h, pBoxes[i].d));
- /* Apparently we're supposed to clip it (gmr test sample) */
- if (pBoxes[i].x + pBoxes[i].w > pMipLevel->size.width)
- pBoxes[i].w = pMipLevel->size.width - pBoxes[i].x;
- if (pBoxes[i].y + pBoxes[i].h > pMipLevel->size.height)
- pBoxes[i].h = pMipLevel->size.height - pBoxes[i].y;
- if (pBoxes[i].z + pBoxes[i].d > pMipLevel->size.depth)
- pBoxes[i].d = pMipLevel->size.depth - pBoxes[i].z;
-
- if ( !pBoxes[i].w
- || !pBoxes[i].h
- || !pBoxes[i].d
- || pBoxes[i].x > pMipLevel->size.width
- || pBoxes[i].y > pMipLevel->size.height
- || pBoxes[i].z > pMipLevel->size.depth)
- {
- Log(("Empty box; skip\n"));
- continue;
- }
-
- uDestOffset = pBoxes[i].x * pSurface->cbBlock + pBoxes[i].y * pMipLevel->cbSurfacePitch + pBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
- AssertReturn(uDestOffset + pBoxes[i].w * pSurface->cbBlock * pBoxes[i].h * pBoxes[i].d <= pMipLevel->cbSurface, VERR_INTERNAL_ERROR);
-
- cbSrcPitch = (guest.pitch == 0) ? pBoxes[i].w * pSurface->cbBlock : guest.pitch;
-
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- (uint8_t *)pMipLevel->pSurfaceData + uDestOffset,
- pMipLevel->cbSurfacePitch,
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + (pBoxes[i].srcy + pBoxes[i].srcz * pBoxes[i].h) * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].d * pBoxes[i].h);
-
- Log4(("first line:\n%.*Rhxd\n", pMipLevel->cbSurfacePitch, pMipLevel->pSurfaceData));
-
- AssertRC(rc);
- }
- pSurface->pMipmapLevels[host.mipmap].fDirty = true;
- pSurface->fDirty = true;
- }
- else
+ case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
+ fRenderTargetTexture = true;
+ /* no break */
+ case SVGA3D_SURFACE_HINT_TEXTURE:
+ fTexture = true;
+ /* no break */
+ case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
+ if (pSurface->fStencilAsTexture)
+ fTexture = true;
+ /* no break */
+ case SVGA3D_SURFACE_HINT_RENDERTARGET:
{
- HRESULT hr = D3D_OK;
- DWORD dwFlags = 0;
-
- /* Flush the drawing pipeline for this surface as it could be used in a shared context. */
- vmsvga3dSurfaceFlush(pThis, pSurface);
+ D3DLOCKED_RECT LockedRect;
+ RECT Rect;
- if (transfer == SVGA3D_READ_HOST_VRAM)
- dwFlags |= D3DLOCK_READONLY;
+ Rect.left = pBox->x;
+ Rect.top = pBox->y;
+ Rect.right = pBox->x + pBox->w; /* exclusive */
+ Rect.bottom = pBox->y + pBox->h; /* exclusive */
- for (unsigned i = 0; i < cCopyBoxes; i++)
+ /* @todo inefficient for VRAM buffers!! */
+ if (fTexture)
{
- bool fTexture = false;
- bool fVertex = false;
- bool fRenderTargetTexture = false;
- unsigned cbSrcPitch;
-
- /* Apparently we're supposed to clip it (gmr test sample) */
- if (pBoxes[i].x + pBoxes[i].w > pMipLevel->size.width)
- pBoxes[i].w = pMipLevel->size.width - pBoxes[i].x;
- if (pBoxes[i].y + pBoxes[i].h > pMipLevel->size.height)
- pBoxes[i].h = pMipLevel->size.height - pBoxes[i].y;
- if (pBoxes[i].z + pBoxes[i].d > pMipLevel->size.depth)
- pBoxes[i].d = pMipLevel->size.depth - pBoxes[i].z;
-
- Assert((pBoxes[i].d == 1 || pBoxes[i].d == 0) && pBoxes[i].z == 0);
-
- if ( !pBoxes[i].w
- || !pBoxes[i].h
- || pBoxes[i].x > pMipLevel->size.width
- || pBoxes[i].y > pMipLevel->size.height)
- {
- Log(("Empty box; skip\n"));
- continue;
- }
-
- cbSrcPitch = (guest.pitch == 0) ? pBoxes[i].w * pSurface->cbBlock : guest.pitch;
-
- switch (pSurface->flags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
- {
- case SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET:
- fRenderTargetTexture = true;
- /* no break */
- case SVGA3D_SURFACE_HINT_TEXTURE:
- fTexture = true;
- /* no break */
- case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
- if (pSurface->fStencilAsTexture)
- fTexture = true;
- /* no break */
- case SVGA3D_SURFACE_HINT_RENDERTARGET:
+ if (pSurface->bounce.pTexture)
{
- D3DLOCKED_RECT LockedRect;
- RECT Rect;
-
- Rect.left = pBoxes[i].x;
- Rect.top = pBoxes[i].y;
- Rect.right = pBoxes[i].x + pBoxes[i].w; /* exclusive */
- Rect.bottom = pBoxes[i].y + pBoxes[i].h; /* exclusive */
-
- /* @todo inefficient for VRAM buffers!! */
- if (fTexture)
+ if ( transfer == SVGA3D_READ_HOST_VRAM
+ && fRenderTargetTexture
+ && iBox == 0 /* only the first time */)
{
- if (pSurface->bounce.pTexture)
+ IDirect3DSurface9 *pSrc, *pDest;
+
+ /* @todo stricter checks for associated context */
+ uint32_t cid = pSurface->idAssociatedContext;
+ if ( cid >= pState->cContexts
+ || pState->papContexts[cid]->id != cid)
{
- if ( transfer == SVGA3D_READ_HOST_VRAM
- && fRenderTargetTexture
- && i == 0 /* only the first time */)
- {
- IDirect3DSurface9 *pSrc, *pDest;
+ Log(("vmsvga3dSurfaceDMA invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ }
+ pContext = pState->papContexts[cid];
- /* @todo stricter checks for associated context */
- uint32_t cid = pSurface->idAssociatedContext;
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSurfaceDMA invalid context id (%x - %x)!\n", cid, (cid >= pState->cContexts) ? -1 : pState->papContexts[cid]->id));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+ /* @todo only sync when something was actually rendered (since the last sync) */
+ Log(("vmsvga3dSurfaceDMA: sync bounce buffer\n"));
+ hr = pSurface->bounce.pTexture->GetSurfaceLevel(uHostMipmap, &pDest);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
- /* @todo only sync when something was actually rendered (since the last sync) */
- Log(("vmsvga3dSurfaceDMA: sync bounce buffer\n"));
- hr = pSurface->bounce.pTexture->GetSurfaceLevel(host.mipmap, &pDest);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ hr = pSurface->u.pTexture->GetSurfaceLevel(uHostMipmap, &pSrc);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
- hr = pSurface->u.pTexture->GetSurfaceLevel(host.mipmap, &pSrc);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetSurfaceLevel failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ hr = pContext->pDevice->GetRenderTargetData(pSrc, pDest);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetRenderTargetData failed with %x\n", hr), VERR_INTERNAL_ERROR);
- hr = pContext->pDevice->GetRenderTargetData(pSrc, pDest);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: GetRenderTargetData failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ pSrc->Release();
+ pDest->Release();
+ }
- pSrc->Release();
- pDest->Release();
- }
+ hr = pSurface->bounce.pTexture->LockRect(uHostMipmap, /* texture level */
+ &LockedRect,
+ &Rect,
+ dwFlags);
+ }
+ else
+ hr = pSurface->u.pTexture->LockRect(uHostMipmap, /* texture level */
+ &LockedRect,
+ &Rect,
+ dwFlags);
+ }
+ else
+ hr = pSurface->u.pSurface->LockRect(&LockedRect,
+ &Rect,
+ dwFlags);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
- hr = pSurface->bounce.pTexture->LockRect(host.mipmap, /* texture level */
- &LockedRect,
- &Rect,
- dwFlags);
- }
- else
- hr = pSurface->u.pTexture->LockRect(host.mipmap, /* texture level */
- &LockedRect,
- &Rect,
- dwFlags);
- }
- else
- hr = pSurface->u.pSurface->LockRect(&LockedRect,
- &Rect,
- dwFlags);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: LockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ if (fTexture)
+ Log(("Lock TEXTURE (bounce=%d) memory for rectangle (%d,%d)(%d,%d)\n", !!(pSurface->bounce.pTexture), Rect.left, Rect.top, Rect.right, Rect.bottom));
+ else
+ Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (pSurface->flags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL) ? "DEPTH-STENCIL" : "RENDERTARGET", Rect.left, Rect.top, Rect.right, Rect.bottom));
+
+ rc = vmsvgaGMRTransfer(pThis,
+ transfer,
+ (uint8_t *)LockedRect.pBits,
+ LockedRect.Pitch,
+ GuestPtr,
+ pBox->srcx * pSurface->cbBlock + pBox->srcy * cbSrcPitch,
+ cbSrcPitch,
+ pBox->w * pSurface->cbBlock,
+ pBox->h);
+ AssertRC(rc);
- if (fTexture)
- Log(("Lock TEXTURE (bounce=%d) memory for rectangle (%d,%d)(%d,%d)\n", !!(pSurface->bounce.pTexture), Rect.left, Rect.top, Rect.right, Rect.bottom));
- else
- Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (pSurface->flags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL) ? "DEPTH-STENCIL" : "RENDERTARGET", Rect.left, Rect.top, Rect.right, Rect.bottom));
-
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- (uint8_t *)LockedRect.pBits,
- LockedRect.Pitch,
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + pBoxes[i].srcy * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].h);
- AssertRC(rc);
+ Log4(("first line:\n%.*Rhxd\n", pBox->w * pSurface->cbBlock, LockedRect.pBits));
- Log4(("first line:\n%.*Rhxd\n", pBoxes[i].w * pSurface->cbBlock, LockedRect.pBits));
+ if (fTexture)
+ {
+ if (pSurface->bounce.pTexture)
+ {
+ hr = pSurface->bounce.pTexture->UnlockRect(uHostMipmap);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
- if (fTexture)
+ if (transfer == SVGA3D_WRITE_HOST_VRAM)
{
- if (pSurface->bounce.pTexture)
+ /* @todo stricter checks for associated context */
+ uint32_t cid = pSurface->idAssociatedContext;
+ if ( cid >= pState->cContexts
+ || pState->papContexts[cid]->id != cid)
{
- hr = pSurface->bounce.pTexture->UnlockRect(host.mipmap);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
-
- if (transfer == SVGA3D_WRITE_HOST_VRAM)
- {
- /* @todo stricter checks for associated context */
- uint32_t cid = pSurface->idAssociatedContext;
- if ( cid >= pState->cContexts
- || pState->papContexts[cid]->id != cid)
- {
- Log(("vmsvga3dSurfaceDMA invalid context id!\n"));
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- }
- PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+ Log(("vmsvga3dSurfaceDMA invalid context id!\n"));
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ }
+ pContext = pState->papContexts[cid];
- Log(("vmsvga3dSurfaceDMA: sync texture from bounce buffer\n"));
+ Log(("vmsvga3dSurfaceDMA: sync texture from bounce buffer\n"));
- /* Copy the new contents to the actual texture object. */
- hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->u.pTexture);
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UpdateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ /* Copy the new contents to the actual texture object. */
+ hr = pContext->pDevice->UpdateTexture(pSurface->bounce.pTexture, pSurface->u.pTexture);
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UpdateTexture failed with %x\n", hr), VERR_INTERNAL_ERROR);
- /* Track the copy operation. */
- vmsvga3dSurfaceTrackUsage(pThis, pContext, pSurface->id);
- }
- }
- else
- hr = pSurface->u.pTexture->UnlockRect(host.mipmap);
+ /* Track the copy operation. */
+ vmsvga3dSurfaceTrackUsage(pState, pContext, pSurface);
}
- else
- hr = pSurface->u.pSurface->UnlockRect();
- AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
- break;
}
+ else
+ hr = pSurface->u.pTexture->UnlockRect(uHostMipmap);
+ }
+ else
+ hr = pSurface->u.pSurface->UnlockRect();
+ AssertMsgReturn(hr == D3D_OK, ("vmsvga3dSurfaceDMA: UnlockRect failed with %x\n", hr), VERR_INTERNAL_ERROR);
+ break;
+ }
- case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
- fVertex = true;
- /* no break */
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ fVertex = true;
+ /* no break */
- case SVGA3D_SURFACE_HINT_INDEXBUFFER:
- {
- uint8_t *pData;
- unsigned uDestOffset;
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ {
+ uint8_t *pData;
+ unsigned uDestOffset;
- uDestOffset = pBoxes[i].x * pSurface->cbBlock + pBoxes[i].y * pSurface->pMipmapLevels[host.mipmap].cbSurfacePitch;
- AssertReturn(uDestOffset + pBoxes[i].w * pSurface->cbBlock + (pBoxes[i].h - 1) * pSurface->pMipmapLevels[host.mipmap].cbSurfacePitch <= pSurface->pMipmapLevels[host.mipmap].cbSurface, VERR_INTERNAL_ERROR);
+ uDestOffset = pBox->x * pSurface->cbBlock + pBox->y * pSurface->pMipmapLevels[uHostMipmap].cbSurfacePitch;
+ AssertReturn(uDestOffset + pBox->w * pSurface->cbBlock + (pBox->h - 1) * pSurface->pMipmapLevels[uHostMipmap].cbSurfacePitch <= pSurface->pMipmapLevels[uHostMipmap].cbSurface, VERR_INTERNAL_ERROR);
- /** @todo lock only as much as we really need */
- if (fVertex)
- hr = pSurface->u.pVertexBuffer->Lock(0, 0, (void **)&pData, dwFlags);
- else
- hr = pSurface->u.pIndexBuffer->Lock(0, 0, (void **)&pData, dwFlags);
- AssertMsg(hr == D3D_OK, ("vmsvga3dSurfaceDMA: Lock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
-
- Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (fVertex) ? "vertex" : "index", pBoxes[i].x, pBoxes[i].y, pBoxes[i].x + pBoxes[i].w, pBoxes[i].y + pBoxes[i].h));
-
- rc = vmsvgaGMRTransfer(pThis,
- transfer,
- pData + uDestOffset,
- pSurface->pMipmapLevels[host.mipmap].cbSurfacePitch,
- guest.ptr,
- pBoxes[i].srcx * pSurface->cbBlock + pBoxes[i].srcy * cbSrcPitch,
- cbSrcPitch,
- pBoxes[i].w * pSurface->cbBlock,
- pBoxes[i].h);
- AssertRC(rc);
+ /** @todo lock only as much as we really need */
+ if (fVertex)
+ hr = pSurface->u.pVertexBuffer->Lock(0, 0, (void **)&pData, dwFlags);
+ else
+ hr = pSurface->u.pIndexBuffer->Lock(0, 0, (void **)&pData, dwFlags);
+ AssertMsg(hr == D3D_OK, ("vmsvga3dSurfaceDMA: Lock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
+
+ Log(("Lock %s memory for rectangle (%d,%d)(%d,%d)\n", (fVertex) ? "vertex" : "index", pBox->x, pBox->y, pBox->x + pBox->w, pBox->y + pBox->h));
+
+ rc = vmsvgaGMRTransfer(pThis,
+ transfer,
+ pData + uDestOffset,
+ pSurface->pMipmapLevels[uHostMipmap].cbSurfacePitch,
+ GuestPtr,
+ pBox->srcx * pSurface->cbBlock + pBox->srcy * cbSrcPitch,
+ cbSrcPitch,
+ pBox->w * pSurface->cbBlock,
+ pBox->h);
+ AssertRC(rc);
- Log4(("first line:\n%.*Rhxd\n", cbSrcPitch, pData));
+ Log4(("first line:\n%.*Rhxd\n", cbSrcPitch, pData));
- if (fVertex)
- hr = pSurface->u.pVertexBuffer->Unlock();
- else
- hr = pSurface->u.pIndexBuffer->Unlock();
- AssertMsg(hr == D3D_OK, ("vmsvga3dSurfaceDMA: Unlock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
- break;
- }
+ if (fVertex)
+ hr = pSurface->u.pVertexBuffer->Unlock();
+ else
+ hr = pSurface->u.pIndexBuffer->Unlock();
+ AssertMsg(hr == D3D_OK, ("vmsvga3dSurfaceDMA: Unlock %s failed with %x\n", (fVertex) ? "vertex" : "index", hr));
+ break;
+ }
- default:
- AssertFailed();
- break;
- }
- }
+ default:
+ AssertFailed();
+ break;
}
+
return rc;
}
+
int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect destRect, SVGA3dSurfaceImageId src, SVGASignedRect srcRect, uint32_t cRects, SVGASignedRect *pRect)
{
/* Requires SVGA_FIFO_CAP_SCREEN_OBJECT support */
@@ -2687,7 +2044,7 @@ int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect d
#if 0
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
HRESULT hr;
PVMSVGA3DSURFACE pSurface;
PVMSVGA3DCONTEXT pContext;
@@ -2729,7 +2086,7 @@ int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect d
int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter filter)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pSurface;
int rc = VINF_SUCCESS;
HRESULT hr;
@@ -2765,7 +2122,7 @@ int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter f
/* Unknown surface type; turn it into a texture. */
Log(("vmsvga3dGenerateMipmaps: unknown src surface id=%x type=%d format=%d -> create texture\n", sid, pSurface->flags, pSurface->format));
- rc = vmsvga3dCreateTexture(pContext, cid, pSurface);
+ rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pSurface);
AssertRCReturn(rc, rc);
}
else
@@ -2782,7 +2139,7 @@ int vmsvga3dGenerateMipmaps(PVGASTATE pThis, uint32_t sid, SVGA3dTextureFilter f
int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3dCopyRect *pRect)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pSurface;
int rc = VINF_SUCCESS;
PVMSVGA3DCONTEXT pContext;
@@ -2832,69 +2189,178 @@ int vmsvga3dCommandPresent(PVGASTATE pThis, uint32_t sid, uint32_t cRects, SVGA3
else
pSurfaceD3D = pSurface->u.pSurface;
- /* Source surface different size? */
- if (pSurface->pMipmapLevels[0].size.width != pThis->svga.uWidth ||
- pSurface->pMipmapLevels[0].size.height != pThis->svga.uHeight)
- {
- float xMultiplier = (float)pSurface->pMipmapLevels[0].size.width / (float)pThis->svga.uWidth;
- float yMultiplier = (float)pSurface->pMipmapLevels[0].size.height / (float)pThis->svga.uHeight;
+ /* Read the destination viewport specs in one go to try avoid some unnecessary update races. */
+ VMSVGAVIEWPORT const DstViewport = pThis->svga.viewport;
+ ASMCompilerBarrier(); /* paranoia */
+ Assert(DstViewport.yHighWC >= DstViewport.yLowWC);
- srcViewPort.x = (uint32_t)((float)pThis->svga.viewport.x * xMultiplier);
- srcViewPort.y = (uint32_t)((float)pThis->svga.viewport.y * yMultiplier);
- srcViewPort.cx = (uint32_t)((float)pThis->svga.viewport.cx * xMultiplier);
- srcViewPort.cy = (uint32_t)((float)pThis->svga.viewport.cy * yMultiplier);
- }
+ /* If there are no recangles specified, just grab a screenful. */
+ SVGA3dCopyRect DummyRect;
+ if (cRects != 0)
+ { /* likely */ }
else
{
- srcViewPort.x = pThis->svga.viewport.x;
- srcViewPort.y = pThis->svga.viewport.y;
- srcViewPort.cx = pThis->svga.viewport.cx;
- srcViewPort.cy = pThis->svga.viewport.cy;
+ /** @todo Find the usecase for this or check what the original device does.
+ * The original code was doing some scaling based on the surface
+ * size... */
+# ifdef DEBUG_bird
+ AssertMsgFailed(("No rects to present. Who is doing that and what do they actually expect?\n"));
+# endif
+ DummyRect.x = DummyRect.srcx = 0;
+ DummyRect.y = DummyRect.srcy = 0;
+ DummyRect.w = pThis->svga.uWidth;
+ DummyRect.h = pThis->svga.uHeight;
+ cRects = 1;
+ pRect = &DummyRect;
}
- /* @note the viewport doesn't affect blitting. */
- if (cRects == 0)
- {
- RECT rectDest, rectSrc;
-
- rectSrc.left = srcViewPort.x;
- rectSrc.top = srcViewPort.y;
- rectSrc.right = rectSrc.left + srcViewPort.cx;
- rectSrc.bottom = rectSrc.top + srcViewPort.cy;
- rectDest.left = 0;
- rectDest.top = 0;
- rectDest.right = pThis->svga.viewport.cx;
- rectDest.bottom = pThis->svga.viewport.cy;
- hr = pContext->pDevice->StretchRect(pSurfaceD3D, &rectSrc, pBackBuffer, &rectDest, D3DTEXF_NONE);
- }
- else
+ /*
+ * Blit the surface rectangle(s) to the back buffer.
+ */
+ uint32_t const cxSurface = pSurface->pMipmapLevels[0].size.width;
+ uint32_t const cySurface = pSurface->pMipmapLevels[0].size.height;
+ for (uint32_t i = 0; i < cRects; i++)
{
- for (uint32_t i = 0; i < cRects; i++)
+ SVGA3dCopyRect ClippedRect = pRect[i];
+
+ /*
+ * Do some sanity checking and limit width and height, all so we
+ * don't need to think about wrap-arounds below.
+ */
+ if (RT_LIKELY( ClippedRect.w
+ && ClippedRect.x < VMSVGA_MAX_X
+ && ClippedRect.srcx < VMSVGA_MAX_X
+ && ClippedRect.h
+ && ClippedRect.y < VMSVGA_MAX_Y
+ && ClippedRect.srcy < VMSVGA_MAX_Y
+ ))
+ { /* likely */ }
+ else
+ continue;
+
+ if (RT_LIKELY(ClippedRect.w < VMSVGA_MAX_Y))
+ { /* likely */ }
+ else
+ ClippedRect.w = VMSVGA_MAX_Y;
+ if (RT_LIKELY(ClippedRect.w < VMSVGA_MAX_Y))
+ { /* likely */ }
+ else
+ ClippedRect.w = VMSVGA_MAX_Y;
+
+ /*
+ * Source surface clipping (paranoia). Straight forward.
+ */
+ if (RT_LIKELY(ClippedRect.srcx < cxSurface))
+ { /* likely */ }
+ else
+ continue;
+ if (RT_LIKELY(ClippedRect.srcx + ClippedRect.w <= cxSurface))
+ { /* likely */ }
+ else
{
- RECT rectSrc;
- RECT rectDest;
+ AssertFailed(); /* remove if annoying. */
+ ClippedRect.w = cxSurface - ClippedRect.srcx;
+ }
+
+ if (RT_LIKELY(ClippedRect.srcy < cySurface))
+ { /* likely */ }
+ else
+ continue;
+ if (RT_LIKELY(ClippedRect.srcy + ClippedRect.h <= cySurface))
+ { /* likely */ }
+ else
+ {
+ AssertFailed(); /* remove if annoying. */
+ ClippedRect.h = cySurface - ClippedRect.srcy;
+ }
- if ( pRect[i].x + pRect[i].w <= pThis->svga.viewport.x
- || pThis->svga.viewport.x + pThis->svga.viewport.cx <= pRect[i].x
- || pRect[i].y + pRect[i].h <= pThis->svga.viewport.y
- || pThis->svga.viewport.y + pThis->svga.viewport.cy <= pRect[i].y)
+ /*
+ * Destination viewport clipping.
+ *
+ * This is very straight forward compared to OpenGL. There is no Y
+ * inversion anywhere and all the coordinate systems are the same.
+ */
+ /* X */
+ if (ClippedRect.x >= DstViewport.x)
+ {
+ if (ClippedRect.x + ClippedRect.w <= DstViewport.xRight)
+ { /* typical */ }
+ else if (ClippedRect.x < DstViewport.xRight)
+ ClippedRect.w = DstViewport.xRight - ClippedRect.x;
+ else
+ continue;
+ }
+ else
+ {
+ uint32_t cxAdjust = DstViewport.x - ClippedRect.x;
+ if (cxAdjust < ClippedRect.w)
{
- /* Intersection is empty; skip */
+ ClippedRect.w -= cxAdjust;
+ ClippedRect.x += cxAdjust;
+ ClippedRect.srcx += cxAdjust;
+ }
+ else
continue;
+
+ if (ClippedRect.x + ClippedRect.w <= DstViewport.xRight)
+ { /* typical */ }
+ else
+ ClippedRect.w = DstViewport.xRight - ClippedRect.x;
+ }
+
+ /* Y */
+ if (ClippedRect.y >= DstViewport.y)
+ {
+ if (ClippedRect.y + ClippedRect.h <= DstViewport.y + DstViewport.cy)
+ { /* typical */ }
+ else if (ClippedRect.x < DstViewport.y + DstViewport.cy)
+ ClippedRect.h = DstViewport.y + DstViewport.cy - ClippedRect.y;
+ else
+ continue;
+ }
+ else
+ {
+ uint32_t cyAdjust = DstViewport.y - ClippedRect.y;
+ if (cyAdjust < ClippedRect.h)
+ {
+ ClippedRect.h -= cyAdjust;
+ ClippedRect.y += cyAdjust;
+ ClippedRect.srcy += cyAdjust;
}
+ else
+ continue;
- rectSrc.left = RT_MAX(pRect[i].srcx, srcViewPort.x);
- rectSrc.top = RT_MAX(pRect[i].srcy, srcViewPort.y);
- rectSrc.right = RT_MIN(pRect[i].srcx + pRect[i].w, srcViewPort.x + srcViewPort.cx);
- rectSrc.bottom = RT_MIN(pRect[i].srcy + pRect[i].h, srcViewPort.y + srcViewPort.cy);
- rectDest.left = RT_MAX(pRect[i].x, pThis->svga.viewport.x) - pThis->svga.viewport.x;
- rectDest.top = RT_MAX(pRect[i].y, pThis->svga.viewport.y) - pThis->svga.viewport.y;
- rectDest.right = RT_MIN(pRect[i].x + pRect[i].w, pThis->svga.viewport.x + pThis->svga.viewport.cx) - pThis->svga.viewport.x;
- rectDest.bottom = RT_MIN(pRect[i].y + pRect[i].h, pThis->svga.viewport.y + pThis->svga.viewport.cy) - pThis->svga.viewport.y;
-
- hr = pContext->pDevice->StretchRect(pSurfaceD3D, &rectSrc, pBackBuffer, &rectDest, D3DTEXF_NONE);
- AssertBreak(hr == D3D_OK);
+ if (ClippedRect.y + ClippedRect.h <= DstViewport.y + DstViewport.cy)
+ { /* typical */ }
+ else
+ ClippedRect.h = DstViewport.y + DstViewport.cy - ClippedRect.y;
}
+
+ /* Calc source rectangle. */
+ RECT SrcRect;
+ SrcRect.left = ClippedRect.srcx;
+ SrcRect.right = ClippedRect.srcx + ClippedRect.w;
+ SrcRect.top = ClippedRect.srcy;
+ SrcRect.bottom = ClippedRect.srcy + ClippedRect.h;
+
+ /* Calc destination rectangle. */
+ RECT DstRect;
+ DstRect.left = ClippedRect.x;
+ DstRect.right = ClippedRect.x + ClippedRect.w;
+ DstRect.top = ClippedRect.y;
+ DstRect.bottom = ClippedRect.y + ClippedRect.h;
+
+ /* Adjust for viewport. */
+ DstRect.left -= DstViewport.x;
+ DstRect.right -= DstViewport.x;
+ DstRect.bottom -= DstViewport.y;
+ DstRect.top -= DstViewport.y;
+
+ Log(("SrcRect: (%d,%d)(%d,%d) DstRect: (%d,%d)(%d,%d)\n",
+ SrcRect.left, SrcRect.bottom, SrcRect.right, SrcRect.top,
+ DstRect.left, DstRect.bottom, DstRect.right, DstRect.top));
+ hr = pContext->pDevice->StretchRect(pSurfaceD3D, &SrcRect, pBackBuffer, &DstRect, D3DTEXF_NONE);
+ AssertBreak(hr == D3D_OK);
}
if (pSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE)
@@ -2923,7 +2389,7 @@ int vmsvga3dContextDefine(PVGASTATE pThis, uint32_t cid)
PVMSVGA3DCONTEXT pContext;
HRESULT hr;
D3DPRESENT_PARAMETERS PresParam;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
AssertReturn(cid < SVGA3D_MAX_CONTEXT_IDS, VERR_INVALID_PARAMETER);
@@ -3009,7 +2475,7 @@ int vmsvga3dContextDefine(PVGASTATE pThis, uint32_t cid)
/* @todo consider using D3DPRESENT_DONOTWAIT so we don't wait for the GPU during Present calls. */
PresParam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
+#ifdef VBOX_VMSVGA3D_WITH_WINE_OPENGL
hr = pState->pD3D9->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
pContext->hwnd,
@@ -3040,7 +2506,7 @@ int vmsvga3dContextDefine(PVGASTATE pThis, uint32_t cid)
*/
int vmsvga3dContextDestroy(PVGASTATE pThis, uint32_t cid)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
AssertReturn(cid < SVGA3D_MAX_CONTEXT_IDS, VERR_INVALID_PARAMETER);
@@ -3162,27 +2628,28 @@ int vmsvga3dContextDestroy(PVGASTATE pThis, uint32_t cid)
return VINF_SUCCESS;
}
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
-#define vmsvga3dContextTrackUsage(pThis, pContext)
-#else
static int vmsvga3dContextTrackUsage(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext)
{
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturn(pState, VERR_NO_MEMORY);
+
/* Inject fences to make sure we can track surface usage in case the client wants to reuse it in another context. */
for (uint32_t i = 0; i < RT_ELEMENTS(pContext->aSidActiveTexture); i++)
{
if (pContext->aSidActiveTexture[i] != SVGA3D_INVALID_ID)
- vmsvga3dSurfaceTrackUsage(pThis, pContext, pContext->aSidActiveTexture[i]);
+ vmsvga3dSurfaceTrackUsageById(pState, pContext, pContext->aSidActiveTexture[i]);
}
if (pContext->sidRenderTarget != SVGA3D_INVALID_ID)
- vmsvga3dSurfaceTrackUsage(pThis, pContext, pContext->sidRenderTarget);
+ vmsvga3dSurfaceTrackUsageById(pState, pContext, pContext->sidRenderTarget);
+#endif
return VINF_SUCCESS;
}
-#endif
/* Handle resize */
int vmsvga3dChangeMode(PVGASTATE pThis)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
/* Resize all active contexts. */
@@ -3318,6 +2785,7 @@ int vmsvga3dChangeMode(PVGASTATE pThis)
Log(("vmsvga3dChangeMode: Resize window %x of context %d to (%d,%d)\n", pContext->hwnd, pContext->id, cs.cx, cs.cy));
+ AssertReturn(pContext->pDevice, VERR_INTERNAL_ERROR);
hr = pContext->pDevice->GetViewport(&viewportOrg);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dChangeMode: GetViewport failed with %x\n", hr), VERR_INTERNAL_ERROR);
@@ -3345,7 +2813,7 @@ int vmsvga3dChangeMode(PVGASTATE pThis)
/* @todo consider using D3DPRESENT_DONOTWAIT so we don't wait for the GPU during Present calls. */
PresParam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;;
-#ifdef VBOX_VMSVGA3D_WITH_OPENGL
+#ifdef VBOX_VMSVGA3D_WITH_WINE_OPENGL
hr = pContext->pDevice->Reset(&PresParam);
AssertMsgReturn(hr == D3D_OK, ("vmsvga3dChangeMode: Reset failed with %x\n", hr), VERR_INTERNAL_ERROR);
#else
@@ -3434,7 +2902,7 @@ int vmsvga3dSetTransform(PVGASTATE pThis, uint32_t cid, SVGA3dTransformType type
D3DTRANSFORMSTATETYPE d3dState;
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetTransform %x %s\n", cid, vmsvgaTransformToString(type)));
@@ -3516,7 +2984,7 @@ int vmsvga3dSetZRange(PVGASTATE pThis, uint32_t cid, SVGA3dZRange zRange)
D3DVIEWPORT9 viewport;
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetZRange %x min=%d max=%d\n", cid, (uint32_t)(zRange.min * 100.0), (uint32_t)(zRange.max * 100.0)));
@@ -3592,7 +3060,7 @@ int vmsvga3dSetRenderState(PVGASTATE pThis, uint32_t cid, uint32_t cRenderStates
DWORD val;
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetRenderState cid=%x cRenderStates=%d\n", cid, cRenderStates));
@@ -4263,7 +3731,7 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
{
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
PVMSVGA3DSURFACE pRenderTarget;
AssertReturn(pState, VERR_NO_MEMORY);
@@ -4370,7 +3838,7 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
|| pRenderTarget->formatD3D == D3DFMT_D24X8))
{
Log(("vmsvga3dSetRenderTarget: Creating stencil surface as texture!\n"));
- int rc = vmsvga3dCreateTexture(pContext, cid, pRenderTarget);
+ int rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pRenderTarget);
AssertRC(rc); /* non-fatal */
}
@@ -4481,11 +3949,11 @@ int vmsvga3dSetRenderTarget(PVGASTATE pThis, uint32_t cid, SVGA3dRenderTargetTyp
if (!pRenderTarget->u.pTexture)
{
Log(("vmsvga3dSetRenderTarget: create texture to be used as render target; surface id=%x type=%d format=%d -> create texture\n", target.sid, pRenderTarget->flags, pRenderTarget->format));
- int rc = vmsvga3dCreateTexture(pContext, cid, pRenderTarget);
+ int rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pRenderTarget);
AssertRCReturn(rc, rc);
}
-#ifndef VBOX_VMSVGA3D_WITH_OPENGL
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
if (pRenderTarget->idAssociatedContext != cid)
{
Log(("vmsvga3dSetRenderTarget; using texture %x created for another context (%d vs %d)\n", target.sid, pRenderTarget->idAssociatedContext, cid));
@@ -4695,7 +4163,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
DWORD val;
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetTextureState %x cTextureState=%d\n", cid, cTextureStates));
@@ -4839,7 +4307,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
{
Assert(pSurface->idAssociatedContext == SVGA3D_INVALID_ID);
Log(("CreateTexture (%d,%d) level=%d fUsage=%x format=%x\n", pSurface->pMipmapLevels[0].size.width, pSurface->pMipmapLevels[0].size.height, pSurface->faces[0].numMipLevels, pSurface->fUsageD3D, pSurface->formatD3D));
- int rc = vmsvga3dCreateTexture(pContext, cid, pSurface);
+ int rc = vmsvga3dBackCreateTexture(pState, pContext, cid, pSurface);
AssertRCReturn(rc, rc);
}
else
@@ -4848,7 +4316,7 @@ int vmsvga3dSetTextureState(PVGASTATE pThis, uint32_t cid, uint32_t cTextureStat
vmsvga3dSurfaceFlush(pThis, pSurface);
}
-#ifndef VBOX_VMSVGA3D_WITH_OPENGL
+#ifndef VBOX_VMSVGA3D_WITH_WINE_OPENGL
if (pSurface->idAssociatedContext != cid)
{
Log(("vmsvga3dSetTextureState; using texture %x created for another context (%d vs %d)\n", sid, pSurface->idAssociatedContext, cid));
@@ -4964,7 +4432,7 @@ int vmsvga3dSetMaterial(PVGASTATE pThis, uint32_t cid, SVGA3dFace face, SVGA3dMa
HRESULT hr;
D3DMATERIAL9 material;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetMaterial %x face %d\n", cid, face));
@@ -5019,7 +4487,7 @@ int vmsvga3dSetLightData(PVGASTATE pThis, uint32_t cid, uint32_t index, SVGA3dLi
HRESULT hr;
D3DLIGHT9 light;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetLightData %x index=%d\n", cid, index));
@@ -5097,7 +4565,7 @@ int vmsvga3dSetLightEnabled(PVGASTATE pThis, uint32_t cid, uint32_t index, uint3
{
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetLightEnabled %x %d -> %d\n", cid, index, enabled));
@@ -5127,7 +4595,7 @@ int vmsvga3dSetViewPort(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
HRESULT hr;
D3DVIEWPORT9 viewPort;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetViewPort %x (%d,%d)(%d,%d)\n", cid, pRect->x, pRect->y, pRect->w, pRect->h));
@@ -5162,7 +4630,7 @@ int vmsvga3dSetClipPlane(PVGASTATE pThis, uint32_t cid, uint32_t index, float p
{
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetClipPlane %x %d (%d,%d)(%d,%d)\n", cid, index, (unsigned)(plane[0] * 100.0), (unsigned)(plane[1] * 100.0), (unsigned)(plane[2] * 100.0), (unsigned)(plane[3] * 100.0)));
@@ -5191,7 +4659,7 @@ int vmsvga3dCommandClear(PVGASTATE pThis, uint32_t cid, SVGA3dClearFlag clearFla
D3DRECT *pRectD3D = NULL;
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dCommandClear %x clearFlag=%x color=%x depth=%d stencil=%x cRects=%d\n", cid, clearFlag, color, (uint32_t)(depth * 100.0), stencil, cRects));
@@ -5234,7 +4702,7 @@ int vmsvga3dCommandClear(PVGASTATE pThis, uint32_t cid, SVGA3dClearFlag clearFla
/* Make sure we can track drawing usage of active render targets. */
if (pContext->sidRenderTarget != SVGA3D_INVALID_ID)
- vmsvga3dSurfaceTrackUsage(pThis, pContext, pContext->sidRenderTarget);
+ vmsvga3dSurfaceTrackUsageById(pState, pContext, pContext->sidRenderTarget);
return VINF_SUCCESS;
}
@@ -5391,7 +4859,7 @@ int vmsvga3dDrawPrimitives(PVGASTATE pThis, uint32_t cid, uint32_t numVertexDecl
uint32_t cVertexDivisor, SVGA3dVertexDivisor *pVertexDivisor)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_INTERNAL_ERROR);
int rc;
HRESULT hr;
@@ -5691,7 +5159,7 @@ int vmsvga3dSetScissorRect(PVGASTATE pThis, uint32_t cid, SVGA3dRect *pRect)
HRESULT hr;
RECT rect;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dSetScissorRect %x (%d,%d)(%d,%d)\n", cid, pRect->x, pRect->y, pRect->w, pRect->h));
@@ -5725,7 +5193,7 @@ int vmsvga3dShaderDefine(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSha
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
PVMSVGA3DSHADER pShader;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dShaderDefine %x shid=%x type=%s cbData=%x\n", cid, shid, (type == SVGA3D_SHADERTYPE_VS) ? "VERTEX" : "PIXEL", cbData));
@@ -5824,7 +5292,7 @@ int vmsvga3dShaderDefine(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSha
int vmsvga3dShaderDestroy(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dShaderType type)
{
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
PVMSVGA3DSHADER pShader = NULL;
@@ -5874,7 +5342,7 @@ int vmsvga3dShaderDestroy(PVGASTATE pThis, uint32_t cid, uint32_t shid, SVGA3dSh
int vmsvga3dShaderSet(PVGASTATE pThis, PVMSVGA3DCONTEXT pContext, uint32_t cid, SVGA3dShaderType type, uint32_t shid)
{
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
HRESULT hr;
@@ -5948,7 +5416,7 @@ int vmsvga3dShaderSetConst(PVGASTATE pThis, uint32_t cid, uint32_t reg, SVGA3dSh
{
HRESULT hr;
PVMSVGA3DCONTEXT pContext;
- PVMSVGA3DSTATE pState = (PVMSVGA3DSTATE)pThis->svga.p3dState;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
AssertReturn(pState, VERR_NO_MEMORY);
Log(("vmsvga3dShaderSetConst %x reg=%x type=%s ctype=%x\n", cid, reg, (type == SVGA3D_SHADERTYPE_VS) ? "VERTEX" : "PIXEL", ctype));
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d.cpp b/src/VBox/Devices/Graphics/DevVGA-SVGA3d.cpp
new file mode 100644
index 0000000..b53119c
--- /dev/null
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d.cpp
@@ -0,0 +1,568 @@
+/* $Id: DevVGA-SVGA3d.cpp $ */
+/** @file
+ * DevSVGA3d - VMWare SVGA device, 3D parts - Common core code.
+ */
+
+/*
+ * Copyright (C) 2013-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+
+#include <VBox/vmm/pgm.h> /* required by DevVGA.h */
+#include <VBox/VBoxVideo.h> /* required by DevVGA.h */
+
+/* should go BEFORE any other DevVGA include to make all DevVGA.h config defines be visible */
+#include "DevVGA.h"
+
+#include "DevVGA-SVGA.h"
+#include "DevVGA-SVGA3d.h"
+#define VMSVGA3D_INCL_STRUCTURE_DESCRIPTORS
+#include "DevVGA-SVGA3d-internal.h"
+
+
+
+/**
+ * Implements the SVGA_3D_CMD_SURFACE_DEFINE_V2 and SVGA_3D_CMD_SURFACE_DEFINE
+ * commands (fifo).
+ *
+ * @returns VBox status code (currently ignored).
+ * @param pThis The VGA device instance data.
+ * @param sid The ID of the surface to (re-)define.
+ * @param surfaceFlags .
+ * @param format .
+ * @param face .
+ * @param multisampleCount .
+ * @param autogenFilter .
+ * @param cMipLevels .
+ * @param paMipLevelSizes .
+ */
+int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format,
+ SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount,
+ SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *paMipLevelSizes)
+{
+ PVMSVGA3DSURFACE pSurface;
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturn(pState, VERR_NO_MEMORY);
+
+ Log(("vmsvga3dSurfaceDefine: sid=%x surfaceFlags=%x format=%s (%x) multiSampleCount=%d autogenFilter=%d, cMipLevels=%d size=(%d,%d,%d)\n",
+ sid, surfaceFlags, vmsvgaLookupEnum((int)format, &g_SVGA3dSurfaceFormat2String), format, multisampleCount, autogenFilter,
+ cMipLevels, paMipLevelSizes->width, paMipLevelSizes->height, paMipLevelSizes->depth));
+
+ AssertReturn(sid < SVGA3D_MAX_SURFACE_IDS, VERR_INVALID_PARAMETER);
+ AssertReturn(cMipLevels >= 1, VERR_INVALID_PARAMETER);
+ /* Assuming all faces have the same nr of mipmaps. */
+ AssertReturn(!(surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels * 6, VERR_INVALID_PARAMETER);
+ AssertReturn((surfaceFlags & SVGA3D_SURFACE_CUBEMAP) || cMipLevels == face[0].numMipLevels, VERR_INVALID_PARAMETER);
+
+ if (sid >= pState->cSurfaces)
+ {
+ /* Grow the array. */
+ uint32_t cNew = RT_ALIGN(sid + 15, 16);
+ void *pvNew = RTMemRealloc(pState->papSurfaces, sizeof(pState->papSurfaces[0]) * cNew);
+ AssertReturn(pvNew, VERR_NO_MEMORY);
+ pState->papSurfaces = (PVMSVGA3DSURFACE *)pvNew;
+ while (pState->cSurfaces < cNew)
+ {
+ pSurface = (PVMSVGA3DSURFACE)RTMemAllocZ(sizeof(*pSurface));
+ AssertReturn(pSurface, VERR_NO_MEMORY);
+ pSurface->id = SVGA3D_INVALID_ID;
+ pState->papSurfaces[pState->cSurfaces++] = pSurface;
+ }
+ }
+ pSurface = pState->papSurfaces[sid];
+
+ /* If one already exists with this id, then destroy it now. */
+ if (pSurface->id != SVGA3D_INVALID_ID)
+ vmsvga3dSurfaceDestroy(pThis, sid);
+
+ RT_ZERO(*pSurface);
+ pSurface->id = sid;
+#ifdef VMSVGA3D_OPENGL
+ pSurface->idWeakContextAssociation = SVGA3D_INVALID_ID;
+#else
+ pSurface->idAssociatedContext = SVGA3D_INVALID_ID;
+#endif
+#ifdef VMSVGA3D_DIRECT3D
+ pSurface->hSharedObject = NULL;
+ pSurface->pSharedObjectTree = NULL;
+#else
+ pSurface->oglId.buffer = OPENGL_INVALID_ID;
+#endif
+
+ /* The surface type is sort of undefined now, even though the hints and format can help to clear that up.
+ * In some case we'll have to wait until the surface is used to create the D3D object.
+ */
+ switch (format)
+ {
+ case SVGA3D_Z_D32:
+ case SVGA3D_Z_D16:
+ case SVGA3D_Z_D24S8:
+ case SVGA3D_Z_D15S1:
+ case SVGA3D_Z_D24X8:
+ case SVGA3D_Z_DF16:
+ case SVGA3D_Z_DF24:
+ case SVGA3D_Z_D24S8_INT:
+ surfaceFlags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
+ break;
+
+ /* Texture compression formats */
+ case SVGA3D_DXT1:
+ case SVGA3D_DXT2:
+ case SVGA3D_DXT3:
+ case SVGA3D_DXT4:
+ case SVGA3D_DXT5:
+ /* Bump-map formats */
+ case SVGA3D_BUMPU8V8:
+ case SVGA3D_BUMPL6V5U5:
+ case SVGA3D_BUMPX8L8V8U8:
+ case SVGA3D_BUMPL8V8U8:
+ case SVGA3D_V8U8:
+ case SVGA3D_Q8W8V8U8:
+ case SVGA3D_CxV8U8:
+ case SVGA3D_X8L8V8U8:
+ case SVGA3D_A2W10V10U10:
+ case SVGA3D_V16U16:
+ /* Typical render target formats; we should allow render target buffers to be used as textures. */
+ case SVGA3D_X8R8G8B8:
+ case SVGA3D_A8R8G8B8:
+ case SVGA3D_R5G6B5:
+ case SVGA3D_X1R5G5B5:
+ case SVGA3D_A1R5G5B5:
+ case SVGA3D_A4R4G4B4:
+ surfaceFlags |= SVGA3D_SURFACE_HINT_TEXTURE;
+ break;
+
+ case SVGA3D_LUMINANCE8:
+ case SVGA3D_LUMINANCE4_ALPHA4:
+ case SVGA3D_LUMINANCE16:
+ case SVGA3D_LUMINANCE8_ALPHA8:
+ case SVGA3D_ARGB_S10E5: /* 16-bit floating-point ARGB */
+ case SVGA3D_ARGB_S23E8: /* 32-bit floating-point ARGB */
+ case SVGA3D_A2R10G10B10:
+ case SVGA3D_ALPHA8:
+ case SVGA3D_R_S10E5:
+ case SVGA3D_R_S23E8:
+ case SVGA3D_RG_S10E5:
+ case SVGA3D_RG_S23E8:
+ case SVGA3D_G16R16:
+ case SVGA3D_A16B16G16R16:
+ case SVGA3D_UYVY:
+ case SVGA3D_YUY2:
+ case SVGA3D_NV12:
+ case SVGA3D_AYUV:
+ case SVGA3D_BC4_UNORM:
+ case SVGA3D_BC5_UNORM:
+ break;
+
+ /*
+ * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
+ * the most efficient format to use when creating new surfaces
+ * expressly for index or vertex data.
+ */
+ case SVGA3D_BUFFER:
+ break;
+
+ default:
+ break;
+ }
+
+ pSurface->flags = surfaceFlags;
+ pSurface->format = format;
+ memcpy(pSurface->faces, face, sizeof(pSurface->faces));
+ pSurface->cFaces = 1; /* check for cube maps later */
+ pSurface->multiSampleCount = multisampleCount;
+ pSurface->autogenFilter = autogenFilter;
+ Assert(autogenFilter != SVGA3D_TEX_FILTER_FLATCUBIC);
+ Assert(autogenFilter != SVGA3D_TEX_FILTER_GAUSSIANCUBIC);
+ pSurface->pMipmapLevels = (PVMSVGA3DMIPMAPLEVEL)RTMemAllocZ(cMipLevels * sizeof(VMSVGA3DMIPMAPLEVEL));
+ AssertReturn(pSurface->pMipmapLevels, VERR_NO_MEMORY);
+
+ for (uint32_t i=0; i < cMipLevels; i++)
+ pSurface->pMipmapLevels[i].size = paMipLevelSizes[i];
+
+ pSurface->cbBlock = vmsvga3dSurfaceFormatSize(format);
+
+#ifdef VMSVGA3D_DIRECT3D
+ /* Translate the format and usage flags to D3D. */
+ pSurface->formatD3D = vmsvga3dSurfaceFormat2D3D(format);
+ pSurface->multiSampleTypeD3D= vmsvga3dMultipeSampleCount2D3D(multisampleCount);
+ pSurface->fUsageD3D = 0;
+ if (surfaceFlags & SVGA3D_SURFACE_HINT_DYNAMIC)
+ pSurface->fUsageD3D |= D3DUSAGE_DYNAMIC;
+ if (surfaceFlags & SVGA3D_SURFACE_HINT_RENDERTARGET)
+ pSurface->fUsageD3D |= D3DUSAGE_RENDERTARGET;
+ if (surfaceFlags & SVGA3D_SURFACE_HINT_DEPTHSTENCIL)
+ pSurface->fUsageD3D |= D3DUSAGE_DEPTHSTENCIL;
+ if (surfaceFlags & SVGA3D_SURFACE_HINT_WRITEONLY)
+ pSurface->fUsageD3D |= D3DUSAGE_WRITEONLY;
+ if (surfaceFlags & SVGA3D_SURFACE_AUTOGENMIPMAPS)
+ pSurface->fUsageD3D |= D3DUSAGE_AUTOGENMIPMAP;
+#else
+ vmsvga3dSurfaceFormat2OGL(pSurface, format);
+#endif
+
+ switch (surfaceFlags & (SVGA3D_SURFACE_HINT_INDEXBUFFER | SVGA3D_SURFACE_HINT_VERTEXBUFFER | SVGA3D_SURFACE_HINT_TEXTURE | SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_CUBEMAP))
+ {
+ case SVGA3D_SURFACE_CUBEMAP:
+ Log(("SVGA3D_SURFACE_CUBEMAP\n"));
+ pSurface->cFaces = 6;
+ break;
+
+ case SVGA3D_SURFACE_HINT_INDEXBUFFER:
+ Log(("SVGA3D_SURFACE_HINT_INDEXBUFFER\n"));
+ /* else type unknown at this time; postpone buffer creation */
+ break;
+
+ case SVGA3D_SURFACE_HINT_VERTEXBUFFER:
+ Log(("SVGA3D_SURFACE_HINT_VERTEXBUFFER\n"));
+ /* Type unknown at this time; postpone buffer creation */
+ break;
+
+ case SVGA3D_SURFACE_HINT_TEXTURE:
+ Log(("SVGA3D_SURFACE_HINT_TEXTURE\n"));
+ break;
+
+ case SVGA3D_SURFACE_HINT_RENDERTARGET:
+ Log(("SVGA3D_SURFACE_HINT_RENDERTARGET\n"));
+ break;
+
+ case SVGA3D_SURFACE_HINT_DEPTHSTENCIL:
+ Log(("SVGA3D_SURFACE_HINT_DEPTHSTENCIL\n"));
+ break;
+
+ default:
+ /* Unknown; decide later. */
+ break;
+ }
+
+ Assert(!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface));
+
+ /* Allocate buffer to hold the surface data until we can move it into a D3D object */
+ for (uint32_t iFace=0; iFace < pSurface->cFaces; iFace++)
+ {
+ for (uint32_t i=0; i < pSurface->faces[iFace].numMipLevels; i++)
+ {
+ uint32_t idx = i + iFace * pSurface->faces[0].numMipLevels;
+
+ Log(("vmsvga3dSurfaceDefine: face %d mip level %d (%d,%d,%d)\n", iFace, i, pSurface->pMipmapLevels[idx].size.width, pSurface->pMipmapLevels[idx].size.height, pSurface->pMipmapLevels[idx].size.depth));
+ Log(("vmsvga3dSurfaceDefine: cbPitch=%x cbBlock=%x \n", pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width, pSurface->cbBlock));
+
+ pSurface->pMipmapLevels[idx].cbSurfacePitch = pSurface->cbBlock * pSurface->pMipmapLevels[idx].size.width;
+ pSurface->pMipmapLevels[idx].cbSurface = pSurface->pMipmapLevels[idx].cbSurfacePitch * pSurface->pMipmapLevels[idx].size.height * pSurface->pMipmapLevels[idx].size.depth;
+ pSurface->pMipmapLevels[idx].pSurfaceData = RTMemAllocZ(pSurface->pMipmapLevels[idx].cbSurface);
+ AssertReturn(pSurface->pMipmapLevels[idx].pSurfaceData, VERR_NO_MEMORY);
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Implements the SVGA_3D_CMD_SURFACE_DESTROY command (fifo).
+ *
+ * @returns VBox status code (currently ignored).
+ * @param pThis The VGA device instance data.
+ * @param sid The ID of the surface to destroy.
+ */
+int vmsvga3dSurfaceDestroy(PVGASTATE pThis, uint32_t sid)
+{
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturn(pState, VERR_NO_MEMORY);
+
+ if ( sid < pState->cSurfaces
+ && pState->papSurfaces[sid]->id == sid)
+ {
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+
+ Log(("vmsvga3dSurfaceDestroy id %x\n", sid));
+
+ /* Check all contexts if this surface is used as a render target or active texture. */
+ for (uint32_t cid = 0; cid < pState->cContexts; cid++)
+ {
+ PVMSVGA3DCONTEXT pContext = pState->papContexts[cid];
+ if (pContext->id == cid)
+ {
+ for (uint32_t i = 0; i < RT_ELEMENTS(pContext->aSidActiveTexture); i++)
+ if (pContext->aSidActiveTexture[i] == sid)
+ pContext->aSidActiveTexture[i] = SVGA3D_INVALID_ID;
+ if (pContext->sidRenderTarget == sid)
+ pContext->sidRenderTarget = SVGA3D_INVALID_ID;
+ }
+ }
+
+ vmsvga3dBackSurfaceDestroy(pState, pSurface);
+
+ if (pSurface->pMipmapLevels)
+ {
+ for (uint32_t face=0; face < pSurface->cFaces; face++)
+ {
+ for (uint32_t i=0; i < pSurface->faces[face].numMipLevels; i++)
+ {
+ uint32_t idx = i + face * pSurface->faces[0].numMipLevels;
+ if (pSurface->pMipmapLevels[idx].pSurfaceData)
+ RTMemFree(pSurface->pMipmapLevels[idx].pSurfaceData);
+ }
+ }
+ RTMemFree(pSurface->pMipmapLevels);
+ }
+
+ memset(pSurface, 0, sizeof(*pSurface));
+ pSurface->id = SVGA3D_INVALID_ID;
+ }
+ else
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Implements the SVGA_3D_CMD_SURFACE_STRETCHBLT command (fifo).
+ *
+ * @returns VBox status code (currently ignored).
+ * @param pThis The VGA device instance data.
+ * @param sid The ID of the surface to destroy.
+ */
+int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId const *pDstSfcImg, SVGA3dBox const *pDstBox,
+ SVGA3dSurfaceImageId const *pSrcSfcImg, SVGA3dBox const *pSrcBox, SVGA3dStretchBltMode enmMode)
+{
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+
+ AssertReturn(pState, VERR_NO_MEMORY);
+
+ uint32_t const sidSrc = pSrcSfcImg->sid;
+ Assert(sidSrc < SVGA3D_MAX_SURFACE_IDS);
+ AssertReturn(sidSrc < pState->cSurfaces, VERR_INVALID_PARAMETER);
+ PVMSVGA3DSURFACE pSrcSurface = pState->papSurfaces[sidSrc];
+ AssertReturn(pSrcSurface && pSrcSurface->id == sidSrc, VERR_INVALID_PARAMETER);
+
+ uint32_t const sidDst = pDstSfcImg->sid;
+ Assert(sidDst < SVGA3D_MAX_SURFACE_IDS);
+ AssertReturn(sidDst < pState->cSurfaces, VERR_INVALID_PARAMETER);
+ PVMSVGA3DSURFACE pDstSurface = pState->papSurfaces[sidDst];
+ AssertReturn(pDstSurface && pDstSurface->id == sidDst, VERR_INVALID_PARAMETER);
+
+ Assert(pSrcSfcImg->face == 0);
+ AssertReturn(pSrcSfcImg->mipmap < pSrcSurface->faces[0].numMipLevels, VERR_INVALID_PARAMETER);
+ Assert(pDstSfcImg->face == 0);
+ AssertReturn(pDstSfcImg->mipmap < pDstSurface->faces[0].numMipLevels, VERR_INVALID_PARAMETER);
+
+ PVMSVGA3DCONTEXT pContext;
+#ifdef VMSVGA3D_OPENGL
+ Log(("vmsvga3dSurfaceStretchBlt: src sid=%x (%d,%d)(%d,%d) dest sid=%x (%d,%d)(%d,%d) mode=%x\n",
+ sidSrc, pSrcBox->x, pSrcBox->y, pSrcBox->x + pSrcBox->w, pSrcBox->y + pSrcBox->h,
+ sidDst, pDstBox->x, pDstBox->y, pDstBox->x + pDstBox->w, pDstBox->y + pDstBox->h, enmMode));
+ pContext = &pState->SharedCtx;
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
+#else
+ Log(("vmsvga3dSurfaceStretchBlt: src sid=%x cid=%x (%d,%d)(%d,%d) dest sid=%x cid=%x (%d,%d)(%d,%d) mode=%x\n",
+ sidSrc, pSrcSurface->idAssociatedContext, pSrcBox->x, pSrcBox->y, pSrcBox->x + pSrcBox->w, pSrcBox->y + pSrcBox->h,
+ sidDst, pDstSurface->idAssociatedContext, pDstBox->x, pDstBox->y, pDstBox->x + pDstBox->w, pDstBox->y + pDstBox->h, enmMode));
+
+ /** @todo stricter checks for associated context */
+ uint32_t cid = pDstSurface->idAssociatedContext;
+ if (cid == SVGA3D_INVALID_ID)
+ cid = pSrcSurface->idAssociatedContext;
+
+ if ( cid >= pState->cContexts
+ || pState->papContexts[cid]->id != cid)
+ {
+ Log(("vmsvga3dSurfaceStretchBlt invalid context id!\n"));
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ }
+ pContext = pState->papContexts[cid];
+#endif
+
+ int rc;
+ if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSrcSurface))
+ {
+ /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
+ Log(("vmsvga3dSurfaceStretchBlt: unknown src surface id=%x type=%d format=%d -> create texture\n", sidSrc, pSrcSurface->flags, pSrcSurface->format));
+ rc = vmsvga3dBackCreateTexture(pState, pContext, pContext->id, pSrcSurface);
+ AssertRCReturn(rc, rc);
+ }
+
+ if (VMSVGA3DSURFACE_HAS_HW_SURFACE(pDstSurface))
+ {
+ /* Unknown surface type; turn it into a texture, which can be used for other purposes too. */
+ Log(("vmsvga3dSurfaceStretchBlt: unknown dest surface id=%x type=%d format=%d -> create texture\n", sidDst, pDstSurface->flags, pDstSurface->format));
+ rc = vmsvga3dBackCreateTexture(pState, pContext, pContext->id, pDstSurface);
+ AssertRCReturn(rc, rc);
+ }
+
+ return vmsvga3dBackSurfaceStretchBlt(pThis, pState,
+ pDstSurface, pDstSfcImg->mipmap, pDstBox,
+ pSrcSurface, pSrcSfcImg->mipmap, pSrcBox,
+ enmMode, pContext);
+}
+
+
+
+/**
+ * Implements the SVGA_3D_CMD_SURFACE_DMA command (fifo).
+ *
+ * @returns VBox status code (currently ignored).
+ * @param pThis The VGA device instance data.
+ * @param guest .
+ * @param host .
+ * @param transfer .
+ * @param cCopyBoxes .
+ * @param paBoxes .
+ */
+int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer,
+ uint32_t cCopyBoxes, SVGA3dCopyBox *paBoxes)
+{
+ int rc = VINF_SUCCESS;
+
+ PVMSVGA3DSTATE pState = pThis->svga.p3dState;
+ AssertReturn(pState, VERR_NO_MEMORY);
+
+ uint32_t sid = host.sid;
+ Assert(sid < SVGA3D_MAX_SURFACE_IDS);
+ AssertReturn(sid < pState->cSurfaces, VERR_INVALID_PARAMETER);
+ PVMSVGA3DSURFACE pSurface = pState->papSurfaces[sid];
+ AssertReturn(pSurface && pSurface->id == sid, VERR_INVALID_PARAMETER);
+
+ AssertMsg(host.face == 0, ("host.face=%#x\n", host.face));
+ AssertReturn(pSurface->faces[0].numMipLevels > host.mipmap, VERR_INVALID_PARAMETER);
+ PVMSVGA3DMIPMAPLEVEL pMipLevel = &pSurface->pMipmapLevels[host.mipmap];
+
+ if (pSurface->flags & SVGA3D_SURFACE_HINT_TEXTURE)
+ Log(("vmsvga3dSurfaceDMA TEXTURE guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
+ else
+ Log(("vmsvga3dSurfaceDMA guestptr gmr=%x offset=%x pitch=%x host sid=%x face=%d mipmap=%d transfer=%s cCopyBoxes=%d\n", guest.ptr.gmrId, guest.ptr.offset, guest.pitch, host.sid, host.face, host.mipmap, (transfer == SVGA3D_WRITE_HOST_VRAM) ? "READ" : "WRITE", cCopyBoxes));
+
+ if (!VMSVGA3DSURFACE_HAS_HW_SURFACE(pSurface))
+ {
+ /*
+ * Not realized in host hardware/library yet, we have to work with
+ * the copy of the data we've got in VMSVGA3DMIMAPLEVEL::pvSurfaceData.
+ */
+ AssertReturn(pSurface->pMipmapLevels[host.mipmap].pSurfaceData, VERR_INTERNAL_ERROR);
+
+ for (unsigned i = 0; i < cCopyBoxes; i++)
+ {
+ unsigned uDestOffset;
+ unsigned cbSrcPitch;
+ uint8_t *pBufferStart;
+
+ Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, paBoxes[i].srcx, paBoxes[i].srcy, paBoxes[i].srcz, paBoxes[i].w, paBoxes[i].h, paBoxes[i].d, paBoxes[i].x, paBoxes[i].y));
+ /* Apparently we're supposed to clip it (gmr test sample) */
+ if (paBoxes[i].x + paBoxes[i].w > pMipLevel->size.width)
+ paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
+ if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
+ paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
+ if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
+ paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;
+
+ if ( !paBoxes[i].w
+ || !paBoxes[i].h
+ || !paBoxes[i].d
+ || paBoxes[i].x > pMipLevel->size.width
+ || paBoxes[i].y > pMipLevel->size.height
+ || paBoxes[i].z > pMipLevel->size.depth)
+ {
+ Log(("Empty box; skip\n"));
+ continue;
+ }
+
+ uDestOffset = paBoxes[i].x * pSurface->cbBlock + paBoxes[i].y * pMipLevel->cbSurfacePitch + paBoxes[i].z * pMipLevel->size.height * pMipLevel->cbSurfacePitch;
+ AssertReturn(uDestOffset + paBoxes[i].w * pSurface->cbBlock * paBoxes[i].h * paBoxes[i].d <= pMipLevel->cbSurface, VERR_INTERNAL_ERROR);
+
+ cbSrcPitch = (guest.pitch == 0) ? paBoxes[i].w * pSurface->cbBlock : guest.pitch;
+#ifdef MANUAL_FLIP_SURFACE_DATA
+ pBufferStart = (uint8_t *)pMipLevel->pSurfaceData
+ + paBoxes[i].x * pSurface->cbBlock
+ + pMipLevel->cbSurface - paBoxes[i].y * pMipLevel->cbSurfacePitch
+ - pMipLevel->cbSurfacePitch; /* flip image during copy */
+#else
+ pBufferStart = (uint8_t *)pMipLevel->pSurfaceData + uDestOffset;
+#endif
+ rc = vmsvgaGMRTransfer(pThis,
+ transfer,
+ pBufferStart,
+#ifdef MANUAL_FLIP_SURFACE_DATA
+ -(int32_t)pMipLevel->cbSurfacePitch,
+#else
+ (int32_t)pMipLevel->cbSurfacePitch,
+#endif
+ guest.ptr,
+ paBoxes[i].srcx * pSurface->cbBlock + (paBoxes[i].srcy + paBoxes[i].srcz * paBoxes[i].h) * cbSrcPitch,
+ cbSrcPitch,
+ paBoxes[i].w * pSurface->cbBlock,
+ paBoxes[i].d * paBoxes[i].h);
+
+ Log4(("first line:\n%.*Rhxd\n", pMipLevel->cbSurfacePitch, pMipLevel->pSurfaceData));
+
+ AssertRC(rc);
+ }
+ pSurface->pMipmapLevels[host.mipmap].fDirty = true;
+ pSurface->fDirty = true;
+ }
+ else
+ {
+ /*
+ * Because of the clipping below, we're doing a little more
+ * here before calling the backend specific code.
+ */
+#ifdef VMSVGA3D_DIRECT3D
+ /* Flush the drawing pipeline for this surface as it could be used in a shared context. */
+ vmsvga3dSurfaceFlush(pThis, pSurface);
+ PVMSVGA3DCONTEXT pContext = NULL;
+
+#else /* VMSVGA3D_OPENGL */
+ PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
+ VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
+#endif
+
+ for (unsigned i = 0; i < cCopyBoxes; i++)
+ {
+ /* Apparently we're supposed to clip it (gmr test sample) */
+ if (paBoxes[i].x + paBoxes[i].w > pMipLevel->size.width)
+ paBoxes[i].w = pMipLevel->size.width - paBoxes[i].x;
+ if (paBoxes[i].y + paBoxes[i].h > pMipLevel->size.height)
+ paBoxes[i].h = pMipLevel->size.height - paBoxes[i].y;
+ if (paBoxes[i].z + paBoxes[i].d > pMipLevel->size.depth)
+ paBoxes[i].d = pMipLevel->size.depth - paBoxes[i].z;
+
+ Assert((paBoxes[i].d == 1 || paBoxes[i].d == 0) && paBoxes[i].z == 0);
+
+ if ( !paBoxes[i].w
+ || !paBoxes[i].h
+ || paBoxes[i].x > pMipLevel->size.width
+ || paBoxes[i].y > pMipLevel->size.height)
+ {
+ Log(("Empty box; skip\n"));
+ continue;
+ }
+
+ Log(("Copy box %d (%d,%d,%d)(%d,%d,%d) dest (%d,%d)\n", i, paBoxes[i].srcx, paBoxes[i].srcy, paBoxes[i].srcz, paBoxes[i].w, paBoxes[i].h, paBoxes[i].d, paBoxes[i].x, paBoxes[i].y));
+
+ uint32_t cbSrcPitch = (guest.pitch == 0) ? paBoxes[i].w * pSurface->cbBlock : guest.pitch;
+ rc = vmsvga3dBackSurfaceDMACopyBox(pThis, pState, pSurface, host.mipmap, guest.ptr, cbSrcPitch, transfer,
+ &paBoxes[i], pContext, rc, i);
+ }
+ }
+
+ return rc;
+}
+
diff --git a/src/VBox/Devices/Graphics/DevVGA-SVGA3d.h b/src/VBox/Devices/Graphics/DevVGA-SVGA3d.h
index f7de518..1388244 100644
--- a/src/VBox/Devices/Graphics/DevVGA-SVGA3d.h
+++ b/src/VBox/Devices/Graphics/DevVGA-SVGA3d.h
@@ -1,3 +1,4 @@
+/* $Id: DevVGA-SVGA3d.h $ */
/** @file
* DevVMWare - VMWare SVGA device - 3D part.
*/
@@ -22,19 +23,6 @@
#include "vmsvga/svga_escape.h"
#include "vmsvga/svga_overlay.h"
-#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
-# include <Windows.h>
-
-# define WM_VMSVGA3D_WAKEUP (WM_APP+1)
-# define WM_VMSVGA3D_CREATEWINDOW (WM_APP+2)
-# define WM_VMSVGA3D_DESTROYWINDOW (WM_APP+3)
-# define WM_VMSVGA3D_RESIZEWINDOW (WM_APP+4)
-# define WM_VMSVGA3D_EXIT (WM_APP+5)
-
-DECLCALLBACK(int) vmsvga3dWindowThread(RTTHREAD ThreadSelf, void *pvUser);
-int vmsvga3dSendThreadMessage(RTTHREAD pWindowThread, RTSEMEVENT WndRequestSem, UINT msg, WPARAM wParam, LPARAM lParam);
-
-#endif
/** Arbitrary limit */
#define SVGA3D_MAX_SHADER_IDS 0x800
@@ -43,22 +31,38 @@ int vmsvga3dSendThreadMessage(RTTHREAD pWindowThread, RTSEMEVENT WndRequestSem,
/** Arbitrary upper limit; seen 8 so far. */
#define SVGA3D_MAX_LIGHTS 32
+
+/**@def FLOAT_FMT_STR
+ * Format string bits to go with FLOAT_FMT_ARGS. */
+#define FLOAT_FMT_STR "%d.%06d"
+/** @def FLOAT_FMT_ARGS
+ * Format arguments for a float value, corresponding to FLOAT_FMT_STR.
+ * @param r The floating point value to format. */
+#define FLOAT_FMT_ARGS(r) (int)(r), ((unsigned)((r) * 1000000) % 1000000U)
+
+
+/* DevVGA-SVGA.cpp: */
void vmsvgaGMRFree(PVGASTATE pThis, uint32_t idGMR);
-int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType, uint8_t *pDest, int32_t cbDestPitch,
- SVGAGuestPtr src, uint32_t offSrc, int32_t cbSrcPitch, uint32_t cbWidth, uint32_t cHeight);
+int vmsvgaGMRTransfer(PVGASTATE pThis, const SVGA3dTransferType enmTransferType, uint8_t *pDest, int32_t cbDestPitch,
+ SVGAGuestPtr src, uint32_t offSrc, int32_t cbSrcPitch, uint32_t cbWidth, uint32_t cHeight);
+void vmsvga3dSurfaceUpdateHeapBuffersOnFifoThread(PVGASTATE pThis, uint32_t sid);
+
+/* DevVGA-SVGA3d-ogl.cpp & DevVGA-SVGA3d-win.cpp: */
int vmsvga3dInit(PVGASTATE pThis);
int vmsvga3dPowerOn(PVGASTATE pThis);
int vmsvga3dLoadExec(PVGASTATE pThis, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
int vmsvga3dSaveExec(PVGASTATE pThis, PSSMHANDLE pSSM);
int vmsvga3dTerminate(PVGASTATE pThis);
int vmsvga3dReset(PVGASTATE pThis);
+void vmsvga3dUpdateHostScreenViewport(PVGASTATE pThis, uint32_t idScreen, VMSVGAVIEWPORT const *pOldViewport);
int vmsvga3dQueryCaps(PVGASTATE pThis, uint32_t idx3dCaps, uint32_t *pu32Val);
int vmsvga3dSurfaceDefine(PVGASTATE pThis, uint32_t sid, uint32_t surfaceFlags, SVGA3dSurfaceFormat format, SVGA3dSurfaceFace face[SVGA3D_MAX_SURFACE_FACES], uint32_t multisampleCount, SVGA3dTextureFilter autogenFilter, uint32_t cMipLevels, SVGA3dSize *pMipLevelSize);
int vmsvga3dSurfaceDestroy(PVGASTATE pThis, uint32_t sid);
int vmsvga3dSurfaceCopy(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dSurfaceImageId src, uint32_t cCopyBoxes, SVGA3dCopyBox *pBox);
-int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId dest, SVGA3dBox destBox, SVGA3dSurfaceImageId src, SVGA3dBox srcBox, SVGA3dStretchBltMode mode);
+int vmsvga3dSurfaceStretchBlt(PVGASTATE pThis, SVGA3dSurfaceImageId const *pDstSfcImg, SVGA3dBox const *pDstBox,
+ SVGA3dSurfaceImageId const *pSrcSfcImg, SVGA3dBox const *pSrcBox, SVGA3dStretchBltMode enmMode);
int vmsvga3dSurfaceDMA(PVGASTATE pThis, SVGA3dGuestImage guest, SVGA3dSurfaceImageId host, SVGA3dTransferType transfer, uint32_t cCopyBoxes, SVGA3dCopyBox *pBoxes);
int vmsvga3dSurfaceBlitToScreen(PVGASTATE pThis, uint32_t dest, SVGASignedRect destRect, SVGA3dSurfaceImageId src, SVGASignedRect srcRect, uint32_t cRects, SVGASignedRect *pRect);
@@ -92,6 +96,114 @@ int vmsvga3dQueryBegin(PVGASTATE pThis, uint32_t cid, SVGA3dQueryType type);
int vmsvga3dQueryEnd(PVGASTATE pThis, uint32_t cid, SVGA3dQueryType type, SVGAGuestPtr guestResult);
int vmsvga3dQueryWait(PVGASTATE pThis, uint32_t cid, SVGA3dQueryType type, SVGAGuestPtr guestResult);
+/* DevVGA-SVGA3d-shared.h: */
+#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
+# include <Windows.h>
+
+# define WM_VMSVGA3D_WAKEUP (WM_APP+1)
+# define WM_VMSVGA3D_CREATEWINDOW (WM_APP+2)
+# define WM_VMSVGA3D_DESTROYWINDOW (WM_APP+3)
+# define WM_VMSVGA3D_RESIZEWINDOW (WM_APP+4)
+# define WM_VMSVGA3D_EXIT (WM_APP+5)
+
+DECLCALLBACK(int) vmsvga3dWindowThread(RTTHREAD ThreadSelf, void *pvUser);
+int vmsvga3dSendThreadMessage(RTTHREAD pWindowThread, RTSEMEVENT WndRequestSem, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#endif
+
+void vmsvga3dUpdateHeapBuffersForSurfaces(PVGASTATE pThis, uint32_t sid);
+void vmsvga3dInfoContextWorker(PVGASTATE pThis, PCDBGFINFOHLP pHlp, uint32_t cid, bool fVerbose);
+void vmsvga3dInfoSurfaceWorker(PVGASTATE pThis, PCDBGFINFOHLP pHlp, uint32_t sid, bool fVerbose, uint32_t cxAscii, bool fInvY);
+
+
+/* DevVGA-SVGA3d-shared.cpp: */
+
+/**
+ * Structure for use with vmsvga3dInfoU32Flags.
+ */
+typedef struct VMSVGAINFOFLAGS32
+{
+ /** The flags. */
+ uint32_t fFlags;
+ /** The corresponding mnemonic. */
+ const char *pszJohnny;
+} VMSVGAINFOFLAGS32;
+/** Pointer to a read-only flag translation entry. */
+typedef VMSVGAINFOFLAGS32 const *PCVMSVGAINFOFLAGS32;
+void vmsvga3dInfoU32Flags(PCDBGFINFOHLP pHlp, uint32_t fFlags, const char *pszPrefix, PCVMSVGAINFOFLAGS32 paFlags, uint32_t cFlags);
+
+/**
+ * Structure for use with vmsvgaFormatEnumValueEx and vmsvgaFormatEnumValue.
+ */
+typedef struct VMSVGAINFOENUM
+{
+ /** The enum value. */
+ int32_t iValue;
+ /** The corresponding value name. */
+ const char *pszName;
+} VMSVGAINFOENUM;
+/** Pointer to a read-only enum value translation entry. */
+typedef VMSVGAINFOENUM const *PCVMSVGAINFOENUM;
+/**
+ * Structure for use with vmsvgaFormatEnumValueEx and vmsvgaFormatEnumValue.
+ */
+typedef struct VMSVGAINFOENUMMAP
+{
+ /** Pointer to the value mapping array. */
+ PCVMSVGAINFOENUM paValues;
+ /** The number of value mappings. */
+ size_t cValues;
+ /** The prefix. */
+ const char *pszPrefix;
+#ifdef RT_STRICT
+ /** Indicates whether we've checked that it's sorted or not. */
+ bool *pfAsserted;
+#endif
+} VMSVGAINFOENUMMAP;
+typedef VMSVGAINFOENUMMAP const *PCVMSVGAINFOENUMMAP;
+/** @def VMSVGAINFOENUMMAP_MAKE
+ * Macro for defining a VMSVGAINFOENUMMAP, silently dealing with pfAsserted.
+ *
+ * @param a_Scope The scope. RT_NOTHING or static.
+ * @param a_VarName The variable name for this map.
+ * @param a_aValues The variable name of the value mapping array.
+ * @param a_pszPrefix The value name prefix.
+ */
+#ifdef VBOX_STRICT
+# define VMSVGAINFOENUMMAP_MAKE(a_Scope, a_VarName, a_aValues, a_pszPrefix) \
+ static bool RT_CONCAT(a_VarName,_AssertedSorted) = false; \
+ a_Scope VMSVGAINFOENUMMAP const a_VarName = { \
+ a_aValues, RT_ELEMENTS(a_aValues), a_pszPrefix, &RT_CONCAT(a_VarName,_AssertedSorted) \
+ }
+#else
+# define VMSVGAINFOENUMMAP_MAKE(a_Scope, a_VarName, a_aValues, a_pszPrefix) \
+ a_Scope VMSVGAINFOENUMMAP const a_VarName = { a_aValues, RT_ELEMENTS(a_aValues), a_pszPrefix }
+#endif
+extern VMSVGAINFOENUMMAP const g_SVGA3dSurfaceFormat2String;
+const char *vmsvgaLookupEnum(int32_t iValue, PCVMSVGAINFOENUMMAP pEnumMap);
+char *vmsvgaFormatEnumValueEx(char *pszBuffer, size_t cbBuffer, const char *pszName, int32_t iValue,
+ bool fPrefix, PCVMSVGAINFOENUMMAP pEnumMap);
+char *vmsvgaFormatEnumValue(char *pszBuffer, size_t cbBuffer, const char *pszName, uint32_t uValue,
+ const char *pszPrefix, const char * const *papszValues, size_t cValues);
+
+/**
+ * ASCII "art" scanline printer callback.
+ *
+ * @param pszLine The line to output.
+ * @param pvUser The user argument.
+ */
+typedef DECLCALLBACK(void) FMVMSVGAASCIIPRINTLN(const char *pszLine, void *pvUser);
+/** Pointer to an ASCII "art" print line callback. */
+typedef FMVMSVGAASCIIPRINTLN *PFMVMSVGAASCIIPRINTLN;
+void vmsvga3dAsciiPrint(PFMVMSVGAASCIIPRINTLN pfnPrintLine, void *pvUser, void const *pvImage, size_t cbImage,
+ uint32_t cx, uint32_t cy, uint32_t cbScanline, SVGA3dSurfaceFormat enmFormat, bool fInvY,
+ uint32_t cchMaxX, uint32_t cchMaxY);
+DECLCALLBACK(void) vmsvga3dAsciiPrintlnInfo(const char *pszLine, void *pvUser);
+DECLCALLBACK(void) vmsvga3dAsciiPrintlnLog(const char *pszLine, void *pvUser);
+
+char *vmsvga3dFormatRenderState(char *pszBuffer, size_t cbBuffer, SVGA3dRenderState const *pRenderState);
+char *vmsvga3dFormatTextureState(char *pszBuffer, size_t cbBuffer, SVGA3dTextureState const *pTextureState);
+void vmsvga3dInfoHostWindow(PCDBGFINFOHLP pHlp, uint64_t idHostWindow);
uint32_t vmsvga3dSurfaceFormatSize(SVGA3dSurfaceFormat format);
diff --git a/src/VBox/Devices/Graphics/DevVGA.cpp b/src/VBox/Devices/Graphics/DevVGA.cpp
index 83cf7c9..ebbb070 100644
--- a/src/VBox/Devices/Graphics/DevVGA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA.cpp
@@ -2201,7 +2201,7 @@ int vgaR3UpdateDisplay(VGAState *s, unsigned xStart, unsigned yStart, unsigned w
* graphic modes
*/
static int vmsvga_draw_graphic(PVGASTATE pThis, bool full_update, bool fFailOnResize, bool reset_dirty,
- PDMIDISPLAYCONNECTOR *pDrv)
+ PDMIDISPLAYCONNECTOR *pDrv)
{
int y, page_min, page_max, linesize, y_start;
int width, height, page0, page1, bwidth, bits;
@@ -2211,8 +2211,11 @@ static int vmsvga_draw_graphic(PVGASTATE pThis, bool full_update, bool fFailOnRe
vga_draw_line_func *vga_draw_line;
if ( pThis->svga.uWidth == VMSVGA_VAL_UNINITIALIZED
+ || pThis->svga.uWidth == 0
|| pThis->svga.uHeight == VMSVGA_VAL_UNINITIALIZED
- || pThis->svga.uBpp == VMSVGA_VAL_UNINITIALIZED)
+ || pThis->svga.uHeight == 0
+ || pThis->svga.uBpp == VMSVGA_VAL_UNINITIALIZED
+ || pThis->svga.uBpp == 0)
{
/* Intermediate state; skip redraws. */
return VINF_SUCCESS;
@@ -4161,10 +4164,9 @@ static DECLCALLBACK(void) vgaInfoState(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, c
pHlp->pfnPrintf(pHlp, "display refresh interval: %u ms\n", pThis->cMilliesRefreshInterval);
#ifdef VBOX_WITH_VMSVGA
- if (pThis->svga.fEnabled) {
+ if (pThis->svga.fEnabled)
pHlp->pfnPrintf(pHlp, pThis->svga.f3DEnabled ? "VMSVGA 3D enabled: %ux%ux%u\n" : "VMSVGA enabled: %ux%ux%u",
pThis->svga.uWidth, pThis->svga.uHeight, pThis->svga.uBpp);
- }
#endif
}
@@ -6064,7 +6066,9 @@ static DECLCALLBACK(int) vgaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
pThis->IPort.pfnCopyRect = vgaPortCopyRect;
pThis->IPort.pfnSetRenderVRAM = vgaPortSetRenderVRAM;
#ifdef VBOX_WITH_VMSVGA
- pThis->IPort.pfnSetViewPort = vmsvgaPortSetViewPort;
+ pThis->IPort.pfnSetViewport = vmsvgaPortSetViewport;
+#else
+ pThis->IPort.pfnSetViewport = NULL;
#endif
pThis->IPort.pfnSendModeHint = vbvaPortSendModeHint;
pThis->IPort.pfnReportHostCursorCapabilities
diff --git a/src/VBox/Devices/Graphics/DevVGA.h b/src/VBox/Devices/Graphics/DevVGA.h
index 4040742..292ed63 100644
--- a/src/VBox/Devices/Graphics/DevVGA.h
+++ b/src/VBox/Devices/Graphics/DevVGA.h
@@ -213,11 +213,12 @@ typedef struct _VBOX_VHWA_PENDINGCMD
#ifdef VBOX_WITH_VMSVGA
-#define VMSVGA_FIFO_EXTCMD_NONE 0
-#define VMSVGA_FIFO_EXTCMD_TERMINATE 1
-#define VMSVGA_FIFO_EXTCMD_SAVESTATE 2
-#define VMSVGA_FIFO_EXTCMD_LOADSTATE 3
-#define VMSVGA_FIFO_EXTCMD_RESET 4
+#define VMSVGA_FIFO_EXTCMD_NONE 0
+#define VMSVGA_FIFO_EXTCMD_TERMINATE 1
+#define VMSVGA_FIFO_EXTCMD_SAVESTATE 2
+#define VMSVGA_FIFO_EXTCMD_LOADSTATE 3
+#define VMSVGA_FIFO_EXTCMD_RESET 4
+#define VMSVGA_FIFO_EXTCMD_UPDATE_SURFACE_HEAP_BUFFERS 5
/** Size of the region to backup when switching into svga mode. */
#define VMSVGA_FRAMEBUFFER_BACKUP_SIZE (32*1024)
@@ -229,7 +230,34 @@ typedef struct
uint32_t uPass;
} VMSVGA_STATE_LOAD, *PVMSVGA_STATE_LOAD;
-typedef struct
+/** Host screen viewport.
+ * (4th quadrant with negated Y values - usual Windows and X11 world view.) */
+typedef struct VMSVGAVIEWPORT
+{
+ uint32_t x; /**< x coordinate (left). */
+ uint32_t y; /**< y coordinate (top). */
+ uint32_t cx; /**< width. */
+ uint32_t cy; /**< height. */
+ /** Right side coordinate (exclusive). Same as x + cx. */
+ uint32_t xRight;
+ /** First quadrant low y coordinate.
+ * Same as y + cy - 1 in window coordinates. */
+ uint32_t yLowWC;
+ /** First quadrant high y coordinate (exclusive) - yLowWC + cy.
+ * Same as y - 1 in window coordinates. */
+ uint32_t yHighWC;
+ /** Alignment padding. */
+ uint32_t uAlignment;
+} VMSVGAVIEWPORT;
+
+/** Pointer to the private VMSVGA ring-3 state structure.
+ * @todo Still not entirely satisfired with the type name, but better than
+ * the previous lower/upper case only distinction. */
+typedef struct VMSVGAR3STATE *PVMSVGAR3STATE;
+/** Pointer to the private (implementation specific) VMSVGA3d state. */
+typedef struct VMSVGA3DSTATE *PVMSVGA3DSTATE;
+
+typedef struct VMSVGAState
{
/** The host window handle */
uint64_t u64HostWindowId;
@@ -238,13 +266,13 @@ typedef struct
/** The R0 FIFO pointer. */
R0PTRTYPE(uint32_t *) pFIFOR0;
/** R3 Opaque pointer to svga state. */
- R3PTRTYPE(void *) pSVGAState;
+ R3PTRTYPE(PVMSVGAR3STATE) pSvgaR3State;
/** R3 Opaque pointer to 3d state. */
- R3PTRTYPE(void *) p3dState;
+ R3PTRTYPE(PVMSVGA3DSTATE) p3dState;
/** R3 Opaque pointer to a copy of the first 32k of the framebuffer before switching into svga mode. */
R3PTRTYPE(void *) pFrameBufferBackup;
/** R3 Opaque pointer to an external fifo cmd parameter. */
- R3PTRTYPE(void *) pFIFOExtCmdParam;
+ R3PTRTYPE(void * volatile) pvFIFOExtCmdParam;
/** Guest physical address of the FIFO memory range. */
RTGCPHYS GCPhysFIFO;
@@ -300,14 +328,10 @@ typedef struct
uint32_t u32MaxWidth;
/** Maximum height supported. */
uint32_t u32MaxHeight;
- /** Viewport rectangle */
- struct
- {
- uint32_t x;
- uint32_t y;
- uint32_t cx;
- uint32_t cy;
- } viewport;
+ /** Viewport rectangle, i.e. what's currently visible of the target host
+ * window. This is usually (0,0)(uWidth,uHeight), but if the window is
+ * shrunk and scrolling applied, both the origin and size may differ. */
+ VMSVGAVIEWPORT viewport;
/** Action flags */
uint32_t u32ActionFlags;
/** SVGA 3d extensions enabled or not. */
@@ -315,8 +339,10 @@ typedef struct
/** VRAM page monitoring enabled or not. */
bool fVRAMTracking;
/** External command to be executed in the FIFO thread. */
- uint8_t u8FIFOExtCommand;
- bool Padding6;
+ uint8_t volatile u8FIFOExtCommand;
+ /** Set by vmsvgaR3RunExtCmdOnFifoThread when it temporarily resumes the FIFO
+ * thread and does not want it do anything but the command. */
+ bool volatile fFifoExtCommandWakeup;
} VMSVGAState;
#endif /* VBOX_WITH_VMSVGA */
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
index a4bd506..094d83e 100644
--- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
@@ -2423,7 +2423,7 @@ static DECLCALLBACK(int) vbvaChannelHandler (void *pvHandler, uint16_t u16Channe
#ifdef VBOX_WITH_VIDEOHWACCEL
case VBVA_VHWA_CMD:
{
- if (cbBuffer < sizeof (VBOXVHWACMD))
+ if (cbBuffer < VBOXVHWACMD_HEADSIZE())
{
rc = VERR_INVALID_PARAMETER;
break;
diff --git a/src/VBox/Devices/Graphics/VBoxSVGA3D.def b/src/VBox/Devices/Graphics/VBoxSVGA3D.def
index 310c7dd..e709519 100644
--- a/src/VBox/Devices/Graphics/VBoxSVGA3D.def
+++ b/src/VBox/Devices/Graphics/VBoxSVGA3D.def
@@ -16,7 +16,7 @@
;
LIBRARY VBoxSVGA3D
-EXPORTS
+EXPORTS
ShaderInitLib
ShaderDestroyLib
ShaderContextCreate
diff --git a/src/VBox/Devices/Graphics/VBoxSVGA3DObjC.def b/src/VBox/Devices/Graphics/VBoxSVGA3DObjC.def
index 9141c42..ca5378e 100644
--- a/src/VBox/Devices/Graphics/VBoxSVGA3DObjC.def
+++ b/src/VBox/Devices/Graphics/VBoxSVGA3DObjC.def
@@ -16,12 +16,14 @@
;
LIBRARY VBoxSVGA3DObjC
-EXPORTS
+EXPORTS
vmsvga3dCocoaServiceRunLoop
vmsvga3dCocoaCreateViewAndContext
- vmsvga3dCocoaDestroyViewAndContext
- vmsvga3dCocoaViewSetPosition
- vmsvga3dCocoaViewSetSize
- vmsvga3dCocoaViewMakeCurrentContext
- vmsvga3dCocoaSwapBuffers
+ vmsvga3dCocoaDestroyViewAndContext
+ vmsvga3dCocoaViewInfo
+ vmsvga3dCocoaViewSetPosition
+ vmsvga3dCocoaViewSetSize
+ vmsvga3dCocoaViewUpdateViewport
+ vmsvga3dCocoaViewMakeCurrentContext
+ vmsvga3dCocoaSwapBuffers
diff --git a/src/VBox/Devices/Graphics/testcase/dump-vmwgfx.c b/src/VBox/Devices/Graphics/testcase/dump-vmwgfx.c
index cbd04a7..0d144af 100644
--- a/src/VBox/Devices/Graphics/testcase/dump-vmwgfx.c
+++ b/src/VBox/Devices/Graphics/testcase/dump-vmwgfx.c
@@ -16,9 +16,9 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#include <assert.h>
#include <dirent.h>
#include <errno.h>
@@ -33,9 +33,9 @@
#include <unistd.h>
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
#define DRM_IOCTL_BASE 'd'
#define DRM_COMMAND_BASE 0x40
#define DRM_VMW_GET_PARAM 0
@@ -58,9 +58,9 @@
#define DRM_VMW_PARAM_MAX_MOB_SIZE 10
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
struct drm_vmw_get_3d_cap_arg
{
uint64_t buffer;
@@ -79,7 +79,7 @@ struct SVGA3dCapsRecord
{
/* Skipped if DRM_VMW_PARAM_MAX_MOB_MEMORY is read. */
struct SVGA3dCapsRecordHeader header;
- uint32_t data[1];
+ uint32_t data[1];
};
struct drm_vmw_getparam_arg
@@ -98,9 +98,9 @@ typedef struct FLAGDESC
typedef FLAGDESC const *PCFLAGDESC;
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
/** The size of the 3D capabilities. */
static uint32_t g_cb3dCaps;
/** Set if the driver will return the new 3D capability format. */
@@ -340,7 +340,7 @@ static int QueryParam(int fd, uint32_t uParam, const char *pszParam)
}
}
else
- printf("%32s: failed: rc=%d errno=%d (%s)\n", pszParam, rc, errno, strerror(errno));
+ printf("%32s: failed: rc=%d errno=%d (%s)\n", pszParam, rc, errno, strerror(errno));
return rc;
}
@@ -595,7 +595,7 @@ int main(int argc, char **argv)
const char *pszDev = "/dev/dri/card0";
if (argc == 2)
pszDev = argv[1];
-
+
int fd = open(pszDev, O_RDWR);
if (fd != -1)
{
@@ -606,7 +606,7 @@ int main(int argc, char **argv)
* Parameters.
*/
rcExit = Dump3DParameters(fd, rcExit);
-
+
/*
* 3D capabilities.
*/
@@ -624,6 +624,6 @@ int main(int argc, char **argv)
fprintf(stderr, "error opening '%s': %d\n", pszDev, errno);
rcExit = 1;
}
-
+
return rcExit;
}
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index 67d8f19..265baeb 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -252,12 +252,18 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
endif
ifdef VBOX_WITH_VMSVGA3D
VBoxDD_DEFS += VBOX_WITH_VMSVGA3D
- VBoxDD_SOURCES += Graphics/DevVGA-SVGA3d-shared.cpp
+ VBoxDD_SOURCES += \
+ Graphics/DevVGA-SVGA3d.cpp \
+ Graphics/DevVGA-SVGA3d-info.cpp \
+ Graphics/DevVGA-SVGA3d-shared.cpp \
+ Graphics/DevVGA-SVGA3d-savedstate.cpp
ifeq ($(KBUILD_TARGET),win) # (Disable this to work with OpenGL on Windows.)
+ VBoxDD_DEFS += VMSVGA3D_DIRECT3D
VBoxDD_SOURCES += Graphics/DevVGA-SVGA3d-win.cpp
VBoxDD_LIBS.win += d3d9.lib $(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/delayimp.lib
VBoxDD_LDFLAGS.win += /DELAYLOAD:d3d9.dll
else
+ VBoxDD_DEFS += VMSVGA3D_OPENGL
VBoxDD_SOURCES += \
Graphics/DevVGA-SVGA3d-ogl.cpp \
$(VBoxDD_0_OUTDIR)/VBoxSVGA3DLazyLoad.asm
@@ -283,7 +289,11 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
VBoxDD_DEFS.darwin += VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE=2.1 VBOX_VMSVGA3D_OTHER_OGL_PROFILE=3.2
endif
endif
- Graphics/DevVGA-SVGA3d-ogl.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
+ Graphics/DevVGA-SVGA3d.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
+ Graphics/DevVGA-SVGA3d-info.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
+ Graphics/DevVGA-SVGA3d-shared.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
+ Graphics/DevVGA-SVGA3d-savedstate.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
+ Graphics/DevVGA-SVGA3d-ogl.cpp_CXXFLAGS.darwin = -F$(VBOX_PATH_MACOSX_SDK_10_7)/System/Library/Frameworks/
endif
ifdef VBOX_WITH_VDMA
diff --git a/src/VBox/Devices/Network/SrvIntNetR0.cpp b/src/VBox/Devices/Network/SrvIntNetR0.cpp
index a28cb53..b5b66c9 100644
--- a/src/VBox/Devices/Network/SrvIntNetR0.cpp
+++ b/src/VBox/Devices/Network/SrvIntNetR0.cpp
@@ -3450,11 +3450,17 @@ static void intnetR0NetworkEditDhcpFromIntNet(PINTNETNETWORK pNetwork, PINTNETSG
intnetR0SgWritePart(pSG, (uintptr_t)&pDhcp->bp_flags - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR), sizeof(uFlags), &uFlags);
/* Patch UDP checksum */
- uint32_t uChecksum = (uint32_t)~pUdpHdr->uh_sum + RT_H2BE_U16_C(RTNET_DHCP_FLAG_BROADCAST);
- while (uChecksum >> 16)
- uChecksum = (uChecksum >> 16) + (uChecksum & 0xFFFF);
- uChecksum = ~uChecksum;
- intnetR0SgWritePart(pSG, (uintptr_t)&pUdpHdr->uh_sum - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR), sizeof(pUdpHdr->uh_sum), &uChecksum);
+ if (pUdpHdr->uh_sum != 0)
+ {
+ uint32_t uChecksum = (uint32_t)~pUdpHdr->uh_sum + RT_H2BE_U16_C(RTNET_DHCP_FLAG_BROADCAST);
+ while (uChecksum >> 16)
+ uChecksum = (uChecksum >> 16) + (uChecksum & 0xFFFF);
+ uChecksum = ~uChecksum;
+ intnetR0SgWritePart(pSG,
+ (uintptr_t)&pUdpHdr->uh_sum - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR),
+ sizeof(pUdpHdr->uh_sum),
+ &uChecksum);
+ }
}
#ifdef RT_OS_DARWIN
diff --git a/src/VBox/Devices/Network/slirp/slirp.c b/src/VBox/Devices/Network/slirp/slirp.c
index c445f2c..1c75fa4 100644
--- a/src/VBox/Devices/Network/slirp/slirp.c
+++ b/src/VBox/Devices/Network/slirp/slirp.c
@@ -304,8 +304,11 @@ int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
int rc;
PNATState pData;
if (u32Netmask & 0x1f)
+ {
/* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
+ LogRel(("The last 5 bits of the netmask (%RTnaipv4) need to be unset\n", RT_BE2H_U32(u32Netmask)));
return VERR_INVALID_PARAMETER;
+ }
pData = RTMemAllocZ(RT_ALIGN_Z(sizeof(NATState), sizeof(uint64_t)));
*ppData = pData;
if (!pData)
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.asm
index 918cfe9..41a6ff4 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.asm
@@ -965,7 +965,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcf8 class=DATA group=DGROUP
section CONST2 progbits vstart=0xda8 align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0da8 LB 0x12
- db 'VirtualBox 4.3.30', 000h
+ db 'VirtualBox 4.3.32', 000h
_bios_prefix_string: ; 0xf0dba LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0dc2 LB 0x6
@@ -16070,4 +16070,4 @@ dummy_iret: ; 0xfff53 LB 0x9d
db 'XM'
cpu_reset: ; 0xffff0 LB 0x10
jmp far 0f000h:0e05bh ; ea 5b e0 00 f0
- db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 002h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 000h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.md5sum
index 519ba64..98b4438 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative.md5sum
@@ -1 +1 @@
-02c411e4ff7982bef1d44e4bd91faac1 *VBoxPcBios.rom
+0c85b0e4727cac0e1be95cd8f912fb59 *VBoxPcBios.rom
diff --git a/src/VBox/Devices/Storage/DevATA.cpp b/src/VBox/Devices/Storage/DevATA.cpp
index c09d339..01dd312 100644
--- a/src/VBox/Devices/Storage/DevATA.cpp
+++ b/src/VBox/Devices/Storage/DevATA.cpp
@@ -4768,60 +4768,128 @@ DECLINLINE(void) ataPIOTransferFinish(PATACONTROLLER pCtl, ATADevState *s)
#endif /* IN_RING3 */
-static int ataDataWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, const uint8_t *pbBuf)
+/**
+ * Fallback for ataCopyPioData124 that handles unaligned and out of bounds cases.
+ *
+ * @param pIf The device interface to work with.
+ * @param pbDst The destination buffer.
+ * @param pbSrc The source buffer.
+ * @param cbCopy The number of bytes to copy, either 1, 2 or 4 bytes.
+ */
+DECL_NO_INLINE(static, void) ataCopyPioData124Slow(ATADevState *pIf, uint8_t *pbDst, const uint8_t *pbSrc, uint32_t cbCopy)
+{
+ uint32_t const offStart = pIf->iIOBufferPIODataStart;
+ uint32_t const offNext = offStart + cbCopy;
+
+ if (offStart + cbCopy > pIf->cbIOBuffer)
+ {
+ Log(("%s: cbCopy=%#x offStart=%#x cbIOBuffer=%#x offNext=%#x (iIOBufferPIODataEnd=%#x)\n",
+ __FUNCTION__, cbCopy, offStart, pIf->cbIOBuffer, offNext, pIf->iIOBufferPIODataEnd));
+ if (offStart < pIf->cbIOBuffer)
+ cbCopy = pIf->cbIOBuffer - offStart;
+ else
+ cbCopy = 0;
+ }
+
+ switch (cbCopy)
+ {
+ case 4: pbDst[3] = pbSrc[3]; /* fall thru */
+ case 3: pbDst[2] = pbSrc[2]; /* fall thru */
+ case 2: pbDst[1] = pbSrc[1]; /* fall thru */
+ case 1: pbDst[0] = pbSrc[0]; /* fall thru */
+ case 0: break;
+ default: AssertFailed(); /* impossible */
+ }
+
+ pIf->iIOBufferPIODataStart = offNext;
+
+}
+
+
+/**
+ * Work for ataDataWrite & ataDataRead that copies data without using memcpy.
+ *
+ * This also updates pIf->iIOBufferPIODataStart.
+ *
+ * The two buffers are either stack (32-bit aligned) or somewhere within
+ * pIf->pbIOBuffer.
+ *
+ * @param pIf The device interface to work with.
+ * @param pbDst The destination buffer.
+ * @param pbSrc The source buffer.
+ * @param cbCopy The number of bytes to copy, either 1, 2 or 4 bytes.
+ */
+DECLINLINE(void) ataCopyPioData124(ATADevState *pIf, uint8_t *pbDst, const uint8_t *pbSrc, uint32_t cbCopy)
+{
+ /*
+ * Quick bounds checking can be done by checking that the pbIOBuffer offset
+ * (iIOBufferPIODataStart) is aligned at the transfer size (which is ASSUMED
+ * to be 1, 2 or 4). However, since we're paranoid and don't currently
+ * trust iIOBufferPIODataEnd to be within bounds, we current check against the
+ * IO buffer size too.
+ */
+ Assert(cbCopy == 1 || cbCopy == 2 || cbCopy == 4);
+ uint32_t const offStart = pIf->iIOBufferPIODataStart;
+ if (RT_LIKELY( !(offStart & (cbCopy - 1))
+ && offStart + cbCopy <= pIf->cbIOBuffer))
+ {
+ switch (cbCopy)
+ {
+ case 4: *(uint32_t *)pbDst = *(uint32_t const *)pbSrc; break;
+ case 2: *(uint16_t *)pbDst = *(uint16_t const *)pbSrc; break;
+ case 1: *pbDst = *pbSrc; break;
+ }
+ pIf->iIOBufferPIODataStart = offStart + cbCopy;
+ }
+ else
+ ataCopyPioData124Slow(pIf, pbDst, pbSrc, cbCopy);
+}
+
+static int ataDataWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, const uint8_t *pbSrc)
{
ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
- uint8_t *p;
if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
{
+ uint8_t *pbDst = s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
+
Assert(s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE);
- p = s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
#ifndef IN_RING3
/* All but the last transfer unit is simple enough for GC, but
* sending a request to the async IO thread is too complicated. */
if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
- {
- memcpy(p, pbBuf, cbSize);
- s->iIOBufferPIODataStart += cbSize;
- }
+ ataCopyPioData124(s, pbDst, pbSrc, cbSize);
else
return VINF_IOM_R3_IOPORT_WRITE;
#else /* IN_RING3 */
- memcpy(p, pbBuf, cbSize);
- s->iIOBufferPIODataStart += cbSize;
+ ataCopyPioData124(s, pbDst, pbSrc, cbSize);
if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
ataPIOTransferFinish(pCtl, s);
#endif /* !IN_RING3 */
}
else
Log2(("%s: DUMMY data\n", __FUNCTION__));
- Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
+ Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, addr, cbSize, pbSrc));
return VINF_SUCCESS;
}
-static int ataDataRead(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, uint8_t *pbBuf)
+static int ataDataRead(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, uint8_t *pbDst)
{
ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
- uint8_t *p;
if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
{
Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
- p = s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
+ uint8_t const *pbSrc = s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
#ifndef IN_RING3
/* All but the last transfer unit is simple enough for GC, but
* sending a request to the async IO thread is too complicated. */
if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
- {
- memcpy(pbBuf, p, cbSize);
- s->iIOBufferPIODataStart += cbSize;
- }
+ ataCopyPioData124(s, pbDst, pbSrc, cbSize);
else
return VINF_IOM_R3_IOPORT_READ;
#else /* IN_RING3 */
- memcpy(pbBuf, p, cbSize);
- s->iIOBufferPIODataStart += cbSize;
+ ataCopyPioData124(s, pbDst, pbSrc, cbSize);
if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
ataPIOTransferFinish(pCtl, s);
#endif /* !IN_RING3 */
@@ -4829,9 +4897,9 @@ static int ataDataRead(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, uint
else
{
Log2(("%s: DUMMY data\n", __FUNCTION__));
- memset(pbBuf, '\xff', cbSize);
+ memset(pbDst, '\xff', cbSize);
}
- Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
+ Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, addr, cbSize, pbDst));
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/VMMDev/VMMDev.cpp b/src/VBox/Devices/VMMDev/VMMDev.cpp
index 26a4f5b..6b4b6c2 100644
--- a/src/VBox/Devices/VMMDev/VMMDev.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDev.cpp
@@ -666,48 +666,58 @@ static int vmmdevReqHandler_ReportGuestUserState(PVMMDEV pThis, VMMDevRequestHea
/*
* Validate input.
*/
- AssertMsgReturn(pReqHdr->size >= sizeof(VMMDevReportGuestUserState), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
- VBoxGuestUserStatus *pStatus = &((VMMDevReportGuestUserState *)pReqHdr)->status;
+ VMMDevReportGuestUserState *pReq = (VMMDevReportGuestUserState *)pReqHdr;
+ AssertMsgReturn(pReq->header.size >= sizeof(*pReq), ("%u\n", pReqHdr->size), VERR_INVALID_PARAMETER);
if ( pThis->pDrv
&& pThis->pDrv->pfnUpdateGuestUserState)
{
- AssertPtr(pStatus);
+ /* Play safe. */
+ AssertReturn(pReq->header.size <= _2K, VERR_TOO_MUCH_DATA);
+ AssertReturn(pReq->status.cbUser <= 256, VERR_TOO_MUCH_DATA);
+ AssertReturn(pReq->status.cbDomain <= 256, VERR_TOO_MUCH_DATA);
+ AssertReturn(pReq->status.cbDetails <= _1K, VERR_TOO_MUCH_DATA);
- if ( pReqHdr->size > _2K
- || pStatus->cbUser > 256
- || pStatus->cbDomain > 256
- || pStatus->cbDetails > _1K) /* Play safe. */
+ /* pbDynamic marks the beginning of the struct's dynamically
+ * allocated data area. */
+ uint8_t *pbDynamic = (uint8_t *)&pReq->status.szUser;
+ uint32_t cbLeft = pReqHdr->size - RT_OFFSETOF(VMMDevReportGuestUserState, status.szUser);
+
+ /* The user. */
+ AssertReturn(pReq->status.cbUser > 0, VERR_INVALID_PARAMETER); /* User name is required. */
+ AssertReturn(pReq->status.cbUser <= cbLeft, VERR_INVALID_PARAMETER);
+ const char *pszUser = (const char *)pbDynamic;
+ AssertReturn(RTStrEnd(pszUser, pReq->status.cbUser), VERR_INVALID_PARAMETER);
+ int rc = RTStrValidateEncoding(pszUser);
+ AssertRCReturn(rc, rc);
+
+ /* Advance to the next field. */
+ pbDynamic += pReq->status.cbUser;
+ cbLeft -= pReq->status.cbUser;
+
+ /* pszDomain can be NULL. */
+ AssertReturn(pReq->status.cbDomain <= cbLeft, VERR_INVALID_PARAMETER);
+ const char *pszDomain = NULL;
+ if (pReq->status.cbDomain)
{
- return VERR_INVALID_PARAMETER;
+ pszDomain = (const char *)pbDynamic;
+ AssertReturn(RTStrEnd(pszDomain, pReq->status.cbDomain), VERR_INVALID_PARAMETER);
+ rc = RTStrValidateEncoding(pszDomain);
+ AssertRCReturn(rc, rc);
+
+ /* Advance to the next field. */
+ pbDynamic += pReq->status.cbDomain;
+ cbLeft -= pReq->status.cbDomain;
}
- /* pyDynamic marks the beginning of the struct's dynamically
- * allocated data area. */
- uint8_t *pvDynamic = (uint8_t *)pStatus + RT_OFFSETOF(VBoxGuestUserStatus, szUser);
- AssertPtr(pvDynamic);
+ /* pbDetails can be NULL. */
+ const uint8_t *pbDetails = NULL;
+ AssertReturn(pReq->status.cbDetails <= cbLeft, VERR_INVALID_PARAMETER);
+ if (pReq->status.cbDetails > 0)
+ pbDetails = pbDynamic;
- if (!pStatus->cbUser) /* User name is required. */
- return VERR_INVALID_PARAMETER;
- const char *pszUser = (const char *)pvDynamic;
- AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
-
- pvDynamic += pStatus->cbUser; /* Advance to next field. */
- const char *pszDomain = pStatus->cbDomain
- ? (const char *)pvDynamic : NULL;
- /* Note: pszDomain can be NULL. */
-
- pvDynamic += pStatus->cbDomain; /* Advance to next field. */
- const uint8_t *puDetails = pStatus->cbDetails
- ? pvDynamic : NULL;
- /* Note: puDetails can be NULL. */
-
- pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain,
- /* State */
- (uint32_t)pStatus->state,
- /* State details */
- puDetails,
- pStatus->cbDetails);
+ pThis->pDrv->pfnUpdateGuestUserState(pThis->pDrv, pszUser, pszDomain, (uint32_t)pReq->status.state,
+ pbDetails, pReq->status.cbDetails);
}
return VINF_SUCCESS;
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index ca41360..33dda88 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -327,7 +327,7 @@ int main()
GEN_CHECK_OFF(VGASTATE, svga.u64HostWindowId);
GEN_CHECK_OFF(VGASTATE, svga.pFIFOR3);
GEN_CHECK_OFF(VGASTATE, svga.pFIFOR0);
- GEN_CHECK_OFF(VGASTATE, svga.pSVGAState);
+ GEN_CHECK_OFF(VGASTATE, svga.pSvgaR3State);
GEN_CHECK_OFF(VGASTATE, svga.p3dState);
GEN_CHECK_OFF(VGASTATE, svga.pFrameBufferBackup);
GEN_CHECK_OFF(VGASTATE, svga.GCPhysFIFO);
diff --git a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
index 4e18afe..37c4917 100644
--- a/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
+++ b/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -131,17 +131,19 @@ private:
};
/**
- * Handler for global events.
+ * Handler for machine events.
*/
-class VirtualBoxEventListener
+class ConsoleEventListener
{
public:
- VirtualBoxEventListener()
+ ConsoleEventListener() :
+ mLastVRDEPort(-1),
+ m_fIgnorePowerOffEvents(false),
+ m_fNoLoggedInUsers(true)
{
- mfNoLoggedInUsers = true;
}
- virtual ~VirtualBoxEventListener()
+ virtual ~ConsoleEventListener()
{
}
@@ -158,6 +160,87 @@ public:
{
switch (aType)
{
+ case VBoxEventType_OnMouseCapabilityChanged:
+ {
+
+ ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
+ Assert(!mccev.isNull());
+
+ BOOL fSupportsAbsolute = false;
+ mccev->COMGETTER(SupportsAbsolute)(&fSupportsAbsolute);
+
+ /* Emit absolute mouse event to actually enable the host mouse cursor. */
+ if (fSupportsAbsolute && gConsole)
+ {
+ ComPtr<IMouse> mouse;
+ gConsole->COMGETTER(Mouse)(mouse.asOutParam());
+ if (mouse)
+ {
+ mouse->PutMouseEventAbsolute(-1, -1, 0, 0 /* Horizontal wheel */, 0);
+ }
+ }
+ break;
+ }
+ case VBoxEventType_OnStateChanged:
+ {
+ ComPtr<IStateChangedEvent> scev = aEvent;
+ Assert(scev);
+
+ MachineState_T machineState;
+ scev->COMGETTER(State)(&machineState);
+
+ /* Terminate any event wait operation if the machine has been
+ * PoweredDown/Saved/Aborted. */
+ if (machineState < MachineState_Running && !m_fIgnorePowerOffEvents)
+ {
+ g_fTerminateFE = true;
+ gEventQ->interruptEventQueueProcessing();
+ }
+
+ break;
+ }
+ case VBoxEventType_OnVRDEServerInfoChanged:
+ {
+ ComPtr<IVRDEServerInfoChangedEvent> rdicev = aEvent;
+ Assert(rdicev);
+
+ if (gConsole)
+ {
+ ComPtr<IVRDEServerInfo> info;
+ gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
+ if (info)
+ {
+ LONG port;
+ info->COMGETTER(Port)(&port);
+ if (port != mLastVRDEPort)
+ {
+ if (port == -1)
+ RTPrintf("VRDE server is inactive.\n");
+ else if (port == 0)
+ RTPrintf("VRDE server failed to start.\n");
+ else
+ RTPrintf("VRDE server is listening on port %d.\n", port);
+
+ mLastVRDEPort = port;
+ }
+ }
+ }
+ break;
+ }
+ case VBoxEventType_OnCanShowWindow:
+ {
+ ComPtr<ICanShowWindowEvent> cswev = aEvent;
+ Assert(cswev);
+ cswev->AddVeto(NULL);
+ break;
+ }
+ case VBoxEventType_OnShowWindow:
+ {
+ ComPtr<IShowWindowEvent> swev = aEvent;
+ Assert(swev);
+ swev->COMSETTER(WinId)(0);
+ break;
+ }
case VBoxEventType_OnGuestPropertyChanged:
{
ComPtr<IGuestPropertyChangedEvent> pChangedEvent = aEvent;
@@ -169,16 +252,8 @@ public:
if (gConsole)
{
hrc = gConsole->COMGETTER(Machine)(pMachine.asOutParam());
- if (SUCCEEDED(hrc) && pMachine)
- {
- Bstr gpMachineId, machineId;
- hrc = pMachine->COMGETTER(Id)(gpMachineId.asOutParam());
- AssertComRC(hrc);
- hrc = pChangedEvent->COMGETTER(MachineId)(machineId.asOutParam());
- AssertComRC(hrc);
- if (gpMachineId != machineId)
- hrc = VBOX_E_OBJECT_NOT_FOUND;
- }
+ if (FAILED(hrc) || !pMachine)
+ hrc = VBOX_E_OBJECT_NOT_FOUND;
}
else
hrc = VBOX_E_INVALID_VM_STATE;
@@ -219,32 +294,32 @@ public:
LogRelFlow(("VRDE: hrc=%Rhrc: Host %s disconnecting clients (current host state known: %s)\n",
hrc, fProcessDisconnectOnGuestLogout ? "will handle" : "does not handle",
- mfNoLoggedInUsers ? "No users logged in" : "Users logged in"));
+ m_fNoLoggedInUsers ? "No users logged in" : "Users logged in"));
if (fProcessDisconnectOnGuestLogout)
{
bool fDropConnection = false;
- if (!mfNoLoggedInUsers) /* Only if the property really changes. */
+ if (!m_fNoLoggedInUsers) /* Only if the property really changes. */
{
if ( utf8Value == "true"
/* Guest property got deleted due to reset,
* so it has no value anymore. */
|| utf8Value.isEmpty())
{
- mfNoLoggedInUsers = true;
+ m_fNoLoggedInUsers = true;
fDropConnection = true;
}
}
else if (utf8Value == "false")
- mfNoLoggedInUsers = false;
+ m_fNoLoggedInUsers = false;
/* Guest property got deleted due to reset,
- * take the shortcut without touching the mfNoLoggedInUsers
+ * take the shortcut without touching the m_fNoLoggedInUsers
* state. */
else if (utf8Value.isEmpty())
fDropConnection = true;
- LogRelFlow(("VRDE: szNoLoggedInUsers=%s, mfNoLoggedInUsers=%RTbool, fDropConnection=%RTbool\n",
- utf8Value.c_str(), mfNoLoggedInUsers, fDropConnection));
+ LogRelFlow(("VRDE: szNoLoggedInUsers=%s, m_fNoLoggedInUsers=%RTbool, fDropConnection=%RTbool\n",
+ utf8Value.c_str(), m_fNoLoggedInUsers, fDropConnection));
if (fDropConnection)
{
@@ -286,128 +361,6 @@ public:
default:
AssertFailed();
}
-
- return S_OK;
- }
-
-private:
-
- bool mfNoLoggedInUsers;
-};
-
-/**
- * Handler for machine events.
- */
-class ConsoleEventListener
-{
-public:
- ConsoleEventListener() :
- mLastVRDEPort(-1),
- m_fIgnorePowerOffEvents(false)
- {
- }
-
- virtual ~ConsoleEventListener()
- {
- }
-
- HRESULT init()
- {
- return S_OK;
- }
-
- void uninit()
- {
- }
-
- STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
- {
- switch (aType)
- {
- case VBoxEventType_OnMouseCapabilityChanged:
- {
-
- ComPtr<IMouseCapabilityChangedEvent> mccev = aEvent;
- Assert(!mccev.isNull());
-
- BOOL fSupportsAbsolute = false;
- mccev->COMGETTER(SupportsAbsolute)(&fSupportsAbsolute);
-
- /* Emit absolute mouse event to actually enable the host mouse cursor. */
- if (fSupportsAbsolute && gConsole)
- {
- ComPtr<IMouse> mouse;
- gConsole->COMGETTER(Mouse)(mouse.asOutParam());
- if (mouse)
- {
- mouse->PutMouseEventAbsolute(-1, -1, 0, 0 /* Horizontal wheel */, 0);
- }
- }
- break;
- }
- case VBoxEventType_OnStateChanged:
- {
- ComPtr<IStateChangedEvent> scev = aEvent;
- Assert(scev);
-
- MachineState_T machineState;
- scev->COMGETTER(State)(&machineState);
-
- /* Terminate any event wait operation if the machine has been
- * PoweredDown/Saved/Aborted. */
- if (machineState < MachineState_Running && !m_fIgnorePowerOffEvents)
- {
- g_fTerminateFE = true;
- gEventQ->interruptEventQueueProcessing();
- }
-
- break;
- }
- case VBoxEventType_OnVRDEServerInfoChanged:
- {
- ComPtr<IVRDEServerInfoChangedEvent> rdicev = aEvent;
- Assert(rdicev);
-
- if (gConsole)
- {
- ComPtr<IVRDEServerInfo> info;
- gConsole->COMGETTER(VRDEServerInfo)(info.asOutParam());
- if (info)
- {
- LONG port;
- info->COMGETTER(Port)(&port);
- if (port != mLastVRDEPort)
- {
- if (port == -1)
- RTPrintf("VRDE server is inactive.\n");
- else if (port == 0)
- RTPrintf("VRDE server failed to start.\n");
- else
- RTPrintf("VRDE server is listening on port %d.\n", port);
-
- mLastVRDEPort = port;
- }
- }
- }
- break;
- }
- case VBoxEventType_OnCanShowWindow:
- {
- ComPtr<ICanShowWindowEvent> cswev = aEvent;
- Assert(cswev);
- cswev->AddVeto(NULL);
- break;
- }
- case VBoxEventType_OnShowWindow:
- {
- ComPtr<IShowWindowEvent> swev = aEvent;
- Assert(swev);
- swev->COMSETTER(WinId)(0);
- break;
- }
- default:
- AssertFailed();
- }
return S_OK;
}
@@ -420,14 +373,13 @@ private:
long mLastVRDEPort;
bool m_fIgnorePowerOffEvents;
+ bool m_fNoLoggedInUsers;
};
typedef ListenerImpl<VirtualBoxClientEventListener> VirtualBoxClientEventListenerImpl;
-typedef ListenerImpl<VirtualBoxEventListener> VirtualBoxEventListenerImpl;
typedef ListenerImpl<ConsoleEventListener> ConsoleEventListenerImpl;
VBOX_LISTENER_DECLARE(VirtualBoxClientEventListenerImpl)
-VBOX_LISTENER_DECLARE(VirtualBoxEventListenerImpl)
VBOX_LISTENER_DECLARE(ConsoleEventListenerImpl)
#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
@@ -1087,6 +1039,7 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
eventTypes.push_back(VBoxEventType_OnVRDEServerInfoChanged);
eventTypes.push_back(VBoxEventType_OnCanShowWindow);
eventTypes.push_back(VBoxEventType_OnShowWindow);
+ eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
CHECK_ERROR(es, RegisterListener(consoleListener, ComSafeArrayAsInParam(eventTypes), true));
}
@@ -1234,26 +1187,6 @@ extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
}
}
- /* VirtualBox events registration. */
- {
- ComPtr<IEventSource> es;
- CHECK_ERROR(virtualBox, COMGETTER(EventSource)(es.asOutParam()));
- ComObjPtr<VirtualBoxEventListenerImpl> listener;
- listener.createObject();
- listener->init(new VirtualBoxEventListener());
- vboxListener = listener;
- com::SafeArray<VBoxEventType_T> eventTypes;
- eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
-
- /**
- * @todo Set the notification pattern to "/VirtualBox/GuestInfo/OS/ *Logged*"
- * to not cause too much load. The current API is broken as
- * IMachine::GuestPropertyNotificationPatterns() would change the
- * filter for _all_ clients. This is not what we want!
- */
- CHECK_ERROR(es, RegisterListener(vboxListener, ComSafeArrayAsInParam(eventTypes), true));
- }
-
#ifdef VBOX_WITH_SAVESTATE_ON_SIGNAL
signal(SIGINT, SaveState);
signal(SIGTERM, SaveState);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
index d6b1f20..eec75e6 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
@@ -597,8 +597,10 @@ int handleModifyHardDisk(HandlerArg *a)
RTMsgError("Resize hard disk operation is not implemented!");
else if (rc == VBOX_E_NOT_SUPPORTED)
RTMsgError("Resize hard disk operation for this format is not implemented yet!");
+ else if (!progress.isNull())
+ CHECK_PROGRESS_ERROR(progress, ("Failed to resize medium"));
else
- CHECK_PROGRESS_ERROR(progress, ("Failed to resize hard disk"));
+ RTMsgError("Failed to resize medium!");
}
}
diff --git a/src/VBox/Frontends/VirtualBox/Makefile.kmk b/src/VBox/Frontends/VirtualBox/Makefile.kmk
index b0828d3..722533b 100644
--- a/src/VBox/Frontends/VirtualBox/Makefile.kmk
+++ b/src/VBox/Frontends/VirtualBox/Makefile.kmk
@@ -66,8 +66,16 @@ src/platform/win/VirtualBoxHardened.rc_DEPS = $(VirtualBox_0_OUTDIR)/VirtualBox
# Include Qt project file, we'll use FORMS and TRANSLATIONS in
# the VirtualBox setup below.
#
+# This is a bit messy. We boldly ASSUME that LANGUAGE, IMAGES, FORMS
+# and TRANSLATIONS are all unused by kBuild and the host toolchain.
+#
SAVED_TEMPLATE := $(TEMPLATE)
include $(PATH_SUB_CURRENT)/VBoxUI.pro
+TEMPLATE := $(SAVED_TEMPLATE)
+SAVED_TEMPLATE :=
+LANGUAGE :=
+IMAGES :=
+# FORMS and TRANSLATIONS are reset further down.
#
@@ -979,6 +987,13 @@ $$(VirtualBox_0_OUTDIR)/VirtualBox-icon.rc: $(MAKEFILE_CURRENT) $(VBOX_WINDOWS_I
endif # win
+#
+# Unset everything that was loaded from VBoxUI.pro.
+#
+FORMS :=
+TRANSLATIONS :=
+
+
ifeq ($(KBUILD_TARGET),darwin)
#
# Create directories for each approved language or the application
@@ -1091,33 +1106,41 @@ if defined(VBOX_WITH_VIDEOHWACCEL)
endif
endif
+
#
# Testcase for the darwin keyboard routines.
#
ifdef VBOX_WITH_TESTCASES
-PROGRAMS.darwin += tstDarwinKeyboard
-tstDarwinKeyboard_NAME = tstDarwinKeyboard
-tstDarwinKeyboard_TEMPLATE = VBOXR3TSTEXE
-tstDarwinKeyboard_DEFS.x86 = USE_HID_FOR_MODIFIERS
-tstDarwinKeyboard_INCS = include
-tstDarwinKeyboard_SOURCES = \
- src/platform/darwin/tstDarwinKeyboard.cpp \
- src/platform/darwin/DarwinKeyboard.cpp
-tstDarwinKeyboard_SOURCES.amd64 = \
- src/platform/darwin/CocoaEventHelper.mm
-tstDarwinKeyboard_LDFLAGS = -framework IOKit -framework Carbon -framework AppKit
-tstDarwinKeyboard_LIBS = \
- $(LIB_RUNTIME)
+ PROGRAMS.darwin += tstDarwinKeyboard
+ tstDarwinKeyboard_TEMPLATE = VBOXR3TSTEXE
+ tstDarwinKeyboard_DEFS.x86 = USE_HID_FOR_MODIFIERS
+ tstDarwinKeyboard_INCS = include
+ tstDarwinKeyboard_SOURCES = \
+ src/platform/darwin/tstDarwinKeyboard.cpp \
+ src/platform/darwin/DarwinKeyboard.cpp
+ tstDarwinKeyboard_SOURCES.amd64 = \
+ src/platform/darwin/CocoaEventHelper.mm
+ tstDarwinKeyboard_LDFLAGS = -framework IOKit -framework Carbon -framework AppKit
+ tstDarwinKeyboard_LIBS = \
+ $(LIB_RUNTIME)
endif
-# Unset everything that was loaded from VBoxUI.pro.
-TEMPLATE := $(SAVED_TEMPLATE)
-SAVED_TEMPLATE :=
-LANGUAGE :=
-FORMS :=
-TRANSLATIONS :=
-IMAGES :=
+#
+# Testcase for SSL certificate downloading.
+#
+if defined(VBOX_WITH_TESTCASES) && defined(VBOX_GUI_WITH_NETWORK_MANAGER)
+ PROGRAMS += tstSSLCertDownloads
+ tstSSLCertDownloads_TEMPLATE = VBOXQT4GUIEXE
+ tstSSLCertDownloads_USES = qt4
+ tstSSLCertDownloads_QTTOOL = QT4
+ tstSSLCertDownloads_QT_MODULES = Core Gui Network
+ tstSSLCertDownloads_DEFS = VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
+ tstSSLCertDownloads_INCS = \
+ $(VBOX_GUI_INC_DIRS)
+ tstSSLCertDownloads_SOURCES = \
+ src/net/tstSSLCertDownloads.cpp
+endif
# Commit the magic.
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
index d42461c..9560147 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
@@ -13,7 +13,7 @@
<location line="+11"/>
<source>--</source>
<comment>Native language country name (empty if this language is for all countries)</comment>
- <translation></translation>
+ <translation>--</translation>
</message>
<message>
<location line="+13"/>
@@ -25,7 +25,7 @@
<location line="+11"/>
<source>--</source>
<comment>Language country name, in English (empty if native country name is empty)</comment>
- <translation></translation>
+ <translation>--</translation>
</message>
<message>
<location line="+13"/>
@@ -104,7 +104,7 @@
<message>
<location line="+5"/>
<source>The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv. Please reinstall the kernel module by executing<br/><br/> <font color=blue>'/etc/init.d/vboxdrv setup'</font><br/><br/>as root. If it is available in your distribution, you should install the DKMS package first. This package keeps track of Linux kernel changes and recompiles the vboxdrv kernel module if necess [...]
- <translation type="unfinished"></translation>
+ <translation>VirtualBox Linux kernel gidatzailea (vboxdrv) ez dago gertatuta edo baimen arazo bat dago /dev/vboxdrv-rekin. Mesedez ber-ezarri kernel moduloa <br/><br/> <font color=blue>'/etc/init.d/vboxdrv setup'</font><br/><br/>exekutatuz erro bezala. Zure banaketan eskuragarri badago, lehenik DKMS paketea ezarri behar duzu. Pakete honek Linux kernelaren aldaketak aztarnatzen ditu eta vboxdrv kernel moduloa berbiltzen du beharrezkoa [...]
</message>
</context>
<context>
@@ -170,10 +170,6 @@
<translation>Ezeztatu</translation>
</message>
<message>
- <source>Ignore</source>
- <translation type="obsolete">Ezikusi</translation>
- </message>
- <message>
<location line="+59"/>
<source>&Details</source>
<translation>&Xehetasunak</translation>
@@ -195,27 +191,6 @@
</message>
</context>
<context>
- <name>QIWidgetValidator</name>
- <message>
- <source>not complete</source>
- <comment>value state</comment>
- <translation type="obsolete">osatu gabe</translation>
- </message>
- <message>
- <source>invalid</source>
- <comment>value state</comment>
- <translation type="obsolete">baliogabea</translation>
- </message>
- <message>
- <source><qt>The value of the <b>%1</b> field on the <b>%2</b> page is %3.</qt></source>
- <translation type="obsolete"><qt><b>%1</b> eremuaren balioa <b>%2</b> orrialdean da %3.</qt></translation>
- </message>
- <message>
- <source><qt>One of the values on the <b>%1</b> page is %2.</qt></source>
- <translation type="obsolete"><qt>Balioetako bat <b>%1</b> orrialdean da %2.</qt></translation>
- </message>
-</context>
-<context>
<name>UIActionPool</name>
<message>
<location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+41"/>
@@ -271,11 +246,7 @@
<message>
<location line="-175"/>
<source>Take a snapshot of the virtual machine</source>
- <translation>Hartu makina birtualaren argazki bat</translation>
- </message>
- <message>
- <source>Show Session Information Dialog</source>
- <translation type="obsolete">Erakutsi Saio Argibide Elkarrizketa</translation>
+ <translation>Hartu makina birtualaren berehalako bat</translation>
</message>
<message>
<location line="+208"/>
@@ -393,7 +364,7 @@
<message>
<location line="+44"/>
<source>&Video Capture</source>
- <translation>&Bideo Harpena</translation>
+ <translation>Bideo &Harpena</translation>
</message>
<message>
<location line="+1"/>
@@ -427,32 +398,16 @@
<translation>&Oharreratzea...</translation>
</message>
<message>
- <source>&Network Adapters...</source>
- <translation type="obsolete">&Sare Egokigailuak...</translation>
- </message>
- <message>
<location line="-269"/>
<source>Change the settings of network adapters</source>
<translation>Aldatu sare egokigailuen ezarpenak</translation>
</message>
<message>
- <source>&Shared Folders...</source>
- <translation type="obsolete">&Elkarbanatutako Agiritegiak...</translation>
- </message>
- <message>
<location line="+43"/>
<source>Create or modify shared folders</source>
<translation>Sortu edo aldatu elkarbanatutako agiritegiak</translation>
</message>
<message>
- <source>&Install Guest Additions...</source>
- <translation type="obsolete">&Ezarri Gonbidatu Gehigarriak...</translation>
- </message>
- <message>
- <source>Mount the Guest Additions installation image</source>
- <translation type="obsolete">Osatu Gonbidatu Gehigarri ezarpen irudia</translation>
- </message>
- <message>
<location line="+151"/>
<source>De&bug</source>
<translation>&Garbitu</translation>
@@ -490,15 +445,6 @@
<translation>Erakutsi Aplikazio Ikurra</translation>
</message>
<message>
- <source>Enable remote desktop (RDP) connections to this machine</source>
- <translation type="obsolete">Gaitu hurruneko mahaigain (RDP) elkarketak makina honetara</translation>
- </message>
- <message>
- <source>Enable &Logging...</source>
- <comment>debug action</comment>
- <translation type="obsolete">Gaitu &Oharreratzea...</translation>
- </message>
- <message>
<location line="-679"/>
<source>Switch to &Fullscreen</source>
<translation>Aldatu &Ikusleiho-osora</translation>
@@ -519,23 +465,11 @@
<translation>Aldatu modu arruntaren eta irudizko mahaigain baterapen moduaren artean</translation>
</message>
<message>
- <source>Switch to &Scale Mode</source>
- <translation type="obsolete">Aldatu &Neurriratu Modura</translation>
- </message>
- <message>
- <source>Switch between normal and scale mode</source>
- <translation type="obsolete">Aldatu modu arrunta eta neurriratu modu artean</translation>
- </message>
- <message>
<location line="+65"/>
<source>Auto-resize &Guest Display</source>
<translation>&Berez-neurriratu Gonbidatu Erakuspena</translation>
</message>
<message>
- <source>Enable R&emote Display</source>
- <translation type="obsolete">Gaitu &Hurruneko Erakuspena</translation>
- </message>
- <message>
<location line="-542"/>
<location filename="../src/selector/UIActionPoolSelector.cpp" line="-416"/>
<source>&Settings...</source>
@@ -598,13 +532,9 @@
<translation>Erakutsi leiho bat produktuaren argibideekin</translation>
</message>
<message>
- <source>Show a dialog with product information</source>
- <translation type="obsolete">Erakutsi elkarrizketa bat produktuaren argibideekin</translation>
- </message>
- <message>
<location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-62"/>
<source>Take Sn&apshot...</source>
- <translation>Hartu &Argazki bat...</translation>
+ <translation>Hartu &Berehalako bat...</translation>
</message>
<message>
<location line="+31"/>
@@ -639,10 +569,6 @@
<translation>&Multimedia Birtual Kudeatzailea...</translation>
</message>
<message>
- <source>Display the Virtual Media Manager dialog</source>
- <translation type="obsolete">Erakutsi Multimedia Birtual Kudeatzaile elkarrizketa</translation>
- </message>
- <message>
<location line="+31"/>
<source>&Import Appliance...</source>
<translation>&Inportatu Makina Birtuala...</translation>
@@ -655,7 +581,7 @@
<message>
<location line="+30"/>
<source>&Export Appliance...</source>
- <translation>&Esportatu Makina Birtuala...</translation>
+ <translation>Esp&ortatu Makina Birtuala...</translation>
</message>
<message>
<location line="+1"/>
@@ -669,10 +595,6 @@
<translation>&Hobespenak...</translation>
</message>
<message>
- <source>Display the global settings dialog</source>
- <translation type="obsolete">Erakutsi ezarpen orokor elkarrizketa</translation>
- </message>
- <message>
<location line="+32"/>
<source>E&xit</source>
<translation>I&rten</translation>
@@ -802,7 +724,7 @@
<message>
<location filename="../src/globals/UIActionPool.cpp" line="-191"/>
<source>Show &Log...</source>
- <translation>Erakutsi O&harra...</translation>
+ <translation>Erakut&si Oharra...</translation>
</message>
<message>
<location line="+82"/>
@@ -817,7 +739,7 @@
<message>
<location line="+54"/>
<source>C&heck for Updates...</source>
- <translation>&Egiaztatu Eguneraketarik dagoen...</translation>
+ <translation>Egi&aztatu Eguneraketarik dagoen...</translation>
</message>
<message>
<location filename="../src/selector/UIActionPoolSelector.cpp" line="-561"/>
@@ -968,10 +890,6 @@
<translation>Arrastatu-eta-Askatu</translation>
</message>
<message>
- <source>Save the virtual machine state</source>
- <translation type="obsolete">Gorde makina birtualaren egoera</translation>
- </message>
- <message>
<location line="-359"/>
<source>Power off the virtual machine</source>
<translation>Itzali makina birtuala</translation>
@@ -1141,304 +1059,12 @@
</message>
</context>
<context>
- <name>UIDescriptionPagePrivate</name>
- <message>
- <source>No description. Press the Edit button below to add it.</source>
- <translation type="obsolete">Azalpen gabe. Sakatu Editatu botoia behean gehitzeko.</translation>
- </message>
- <message>
- <source>Edit</source>
- <translation type="obsolete">Editatu</translation>
- </message>
- <message>
- <source>Edit (Ctrl+E)</source>
- <translation type="obsolete">Editatu (Ctrl+E)</translation>
- </message>
-</context>
-<context>
- <name>UIDetailsBlock</name>
- <message>
- <source>Name</source>
- <comment>details report</comment>
- <translation type="obsolete">Izena</translation>
- </message>
- <message>
- <source>OS Type</source>
- <comment>details report</comment>
- <translation type="obsolete">SE Mota</translation>
- </message>
- <message>
- <source>Information inaccessible</source>
- <comment>details report</comment>
- <translation type="obsolete">Argibideak eskuraezin</translation>
- </message>
- <message>
- <source>Base Memory</source>
- <comment>details report</comment>
- <translation type="obsolete">Ohinarri Oroimena</translation>
- </message>
- <message>
- <source><nobr>%1 MB</nobr></source>
- <comment>details report</comment>
- <translation type="obsolete"><nobr>%1 MB</nobr></translation>
- </message>
- <message>
- <source>Processors</source>
- <comment>details report</comment>
- <translation type="obsolete">Prozesagailuak</translation>
- </message>
- <message>
- <source><nobr>%1</nobr></source>
- <comment>details report</comment>
- <translation type="obsolete"><nobr>%1</nobr></translation>
- </message>
- <message>
- <source><nobr>%1%</nobr></source>
- <comment>details report</comment>
- <translation type="obsolete"><nobr>%1%</nobr></translation>
- </message>
- <message>
- <source>Boot Order</source>
- <comment>details report</comment>
- <translation type="obsolete">Abiarazpen Hurrenkera</translation>
- </message>
- <message>
- <source>ACPI</source>
- <comment>details report</comment>
- <translation type="obsolete">ACPI</translation>
- </message>
- <message>
- <source>IO APIC</source>
- <comment>details report</comment>
- <translation type="obsolete">IO APIC</translation>
- </message>
- <message>
- <source>BIOS</source>
- <comment>details report</comment>
- <translation type="obsolete">BIOS</translation>
- </message>
- <message>
- <source>VT-x/AMD-V</source>
- <comment>details report</comment>
- <translation type="obsolete">VT-x/AMD-V</translation>
- </message>
- <message>
- <source>PAE/NX</source>
- <comment>details report</comment>
- <translation type="obsolete">PAE/NX</translation>
- </message>
- <message>
- <source>Acceleration</source>
- <comment>details report</comment>
- <translation type="obsolete">Bizkorpena</translation>
- </message>
- <message>
- <source>Video Memory</source>
- <comment>details report</comment>
- <translation type="obsolete">Bideo Oroimena</translation>
- </message>
- <message>
- <source>Screens</source>
- <comment>details report</comment>
- <translation type="obsolete">Ikusleihoak</translation>
- </message>
- <message>
- <source>2D Video</source>
- <comment>details report</comment>
- <translation type="obsolete">2D Bideoa</translation>
- </message>
- <message>
- <source>3D</source>
- <comment>details report</comment>
- <translation type="obsolete">3D</translation>
- </message>
- <message>
- <source>Remote Desktop Server Port</source>
- <comment>details report (VRDE Server)</comment>
- <translation type="obsolete">Hurruneko Mahaigain Zerbitzari Ataka</translation>
- </message>
- <message>
- <source>Remote Desktop Server</source>
- <comment>details report (VRDE Server)</comment>
- <translation type="obsolete">Hurruneko Mahaigain Zerbitzaria</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (VRDE Server)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>(CD/DVD)</source>
- <translation type="obsolete">(CD/DVD)</translation>
- </message>
- <message>
- <source>Not Attached</source>
- <comment>details report (Storage)</comment>
- <translation type="obsolete">Erantsi gabe</translation>
- </message>
- <message>
- <source>Host Driver</source>
- <comment>details report (audio)</comment>
- <translation type="obsolete">Hostalari Gidagailua</translation>
- </message>
- <message>
- <source>Controller</source>
- <comment>details report (audio)</comment>
- <translation type="obsolete">Kontrolatzailea</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (audio)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>Bridged adapter, %1</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Zubi egokitzailea, %1</translation>
- </message>
- <message>
- <source>Internal network, '%1'</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Barneko sarea, '%1'</translation>
- </message>
- <message>
- <source>Generic driver, '%1'</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Gidagailu generikoa, '%1'</translation>
- </message>
- <message>
- <source>Generic driver, '%1' { %2 }</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Gidagailu generikoa, '%1' { %2 }</translation>
- </message>
- <message>
- <source>Adapter %1</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Egokitzailea %1</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (network)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>Port %1</source>
- <comment>details report (serial ports)</comment>
- <translation type="obsolete">Ataka %1</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (serial ports)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>Port %1</source>
- <comment>details report (parallel ports)</comment>
- <translation type="obsolete">Ataka %1</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (parallel ports)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>Device Filters</source>
- <comment>details report (USB)</comment>
- <translation type="obsolete">Gailu Iragazkiak</translation>
- </message>
- <message>
- <source>%1 (%2 active)</source>
- <comment>details report (USB)</comment>
- <translation type="obsolete">%1 (%2 gaituta)</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (USB)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
- <source>Shared Folders</source>
- <comment>details report (shared folders)</comment>
- <translation type="obsolete">Elkarbanatutako Agiritegiak</translation>
- </message>
- <message>
- <source>None</source>
- <comment>details report (shared folders)</comment>
- <translation type="obsolete">Ezer ez</translation>
- </message>
- <message>
- <source>None</source>
- <comment>details report (description)</comment>
- <translation type="obsolete">Ezer ez</translation>
- </message>
-</context>
-<context>
<name>UIDetailsPagePrivate</name>
<message>
<location filename="../src/selector/UIVMDesktop.cpp" line="+134"/>
<source>The selected virtual machine is <i>inaccessible</i>. Please inspect the error message shown below and press the <b>Refresh</b> button if you want to repeat the accessibility check:</source>
<translation>Hautaturiko makina birtuala <i>eskuraezina</i> da. Mesedez aztertu behean erakusten den akats mezua eta sakatu <b>Berritu</b> botoia sarbidetasun egiaztapena berregitea nahi baduzu:</translation>
</message>
- <message>
- <source>General</source>
- <comment>details report</comment>
- <translation type="obsolete">Orokorra</translation>
- </message>
- <message>
- <source>System</source>
- <comment>details report</comment>
- <translation type="obsolete">Sistema</translation>
- </message>
- <message>
- <source>Preview</source>
- <comment>details report</comment>
- <translation type="obsolete">Aurreikuspena</translation>
- </message>
- <message>
- <source>Display</source>
- <comment>details report</comment>
- <translation type="obsolete">Erakutsi</translation>
- </message>
- <message>
- <source>Storage</source>
- <comment>details report</comment>
- <translation type="obsolete">Biltegia</translation>
- </message>
- <message>
- <source>Audio</source>
- <comment>details report</comment>
- <translation type="obsolete">Audioa</translation>
- </message>
- <message>
- <source>Network</source>
- <comment>details report</comment>
- <translation type="obsolete">Sarea</translation>
- </message>
- <message>
- <source>Serial Ports</source>
- <comment>details report</comment>
- <translation type="obsolete">Serieko Atakak</translation>
- </message>
- <message>
- <source>Parallel Ports</source>
- <comment>details report</comment>
- <translation type="obsolete">Ataka Kidetuak</translation>
- </message>
- <message>
- <source>USB</source>
- <comment>details report</comment>
- <translation type="obsolete">USB</translation>
- </message>
- <message>
- <source>Shared Folders</source>
- <comment>details report</comment>
- <translation type="obsolete">Elkarbanatutako Agiritegiak</translation>
- </message>
- <message>
- <source>Description</source>
- <comment>details report</comment>
- <translation type="obsolete">Azalpena</translation>
- </message>
</context>
<context>
<name>UIDnDHandler</name>
@@ -1579,7 +1205,7 @@
<message>
<location line="+2"/>
<source>Exit group</source>
- <translation>Irten taldetik</translation>
+ <translation>Atera taldetik</translation>
</message>
</context>
<context>
@@ -1894,7 +1520,7 @@
<location line="+234"/>
<source>Device Filters</source>
<comment>details (usb)</comment>
- <translation>Gailu Iragakiak</translation>
+ <translation>Gailu Iragazkiak</translation>
</message>
<message>
<location line="+7"/>
@@ -1977,17 +1603,17 @@
<message>
<location line="+7"/>
<source>Machine Windows:</source>
- <translation type="unfinished"></translation>
+ <translation>Makinaren Leihoak:</translation>
</message>
<message>
<location line="+16"/>
<source>If checked, machine windows will be raised when the mouse pointer moves over them.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, makinaren leihoak jaso egingo dira saguaren punta gainean mugitzerakoan.</translation>
</message>
<message>
<location line="+3"/>
<source>&Raise Window Under Mouse</source>
- <translation type="unfinished"></translation>
+ <translation>&Jaso Leihoa Sagu Azpian</translation>
</message>
<message>
<location filename="../src/settings/global/UIGlobalSettingsDisplay.cpp" line="+182"/>
@@ -2015,7 +1641,7 @@
<location line="+2"/>
<source>Hint</source>
<comment>Maximum Guest Screen Size</comment>
- <translation type="unfinished"></translation>
+ <translation>Zehaztu</translation>
</message>
<message>
<location line="+2"/>
@@ -2026,10 +1652,6 @@
<context>
<name>UIGlobalSettingsExtension</name>
<message>
- <source>&Extension Packages:</source>
- <translation type="obsolete">&Hedapen Paketeak:</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsExtension.ui" line="+24"/>
<source>&Extension Packages</source>
<translation>&Hedapen Paketeak</translation>
@@ -2084,14 +1706,6 @@
<context>
<name>UIGlobalSettingsGeneral</name>
<message>
- <source>Displays the path to the default virtual machine folder. This folder is used, if not explicitly specified otherwise, when creating new virtual machines.</source>
- <translation type="obsolete">Makina birtualaren berezko agiritegi helburua erakusten du. Agiritegi hau erabiltzen da, ez bada besterik adierazten, makina birtual berriak sortzerakoan.</translation>
- </message>
- <message>
- <source>Displays the path to the library that provides authentication for Remote Display (VRDP) clients.</source>
- <translation type="obsolete">Hurruneko Erakuspen (VRDP) bezeroentzako egiaztapena hornitzen duen liburutegirako helburua erakusten du.</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsGeneral.ui" line="+24"/>
<source>Default &Machine Folder:</source>
<translation>Berezko &Makina Agiritegia:</translation>
@@ -2099,17 +1713,17 @@
<message>
<location line="+19"/>
<source>Holds the path to the default virtual machine folder. This folder is used, if not explicitly specified otherwise, when creating new virtual machines.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualaren berezko agiritegi helburua zehazten du. Agiritegi hau erabiltzen da, ez bada besterik adierazten, makina birtual berriak sortzerakoan.</translation>
</message>
<message>
<location line="+7"/>
<source>V&RDP Authentication Library:</source>
- <translation>V&RDP Egiaztapen Liburutegia:</translation>
+ <translation>VRDP &Egiaztapen Liburutegia:</translation>
</message>
<message>
<location line="+19"/>
<source>Holds the path to the library that provides authentication for Remote Display (VRDP) clients.</source>
- <translation type="unfinished"></translation>
+ <translation>Hurruneko Erakuspen (VRDP) bezeroentzako egiaztapena hornitzen duen liburutegirako helburua zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2141,38 +1755,10 @@
<source>Disable When Running Virtual Machines</source>
<translation>Ezgaitu Makina Birtualak Ekinean daudenean</translation>
</message>
- <message>
- <source>When checked, the application will provide an icon with the context menu in the system tray.</source>
- <translation type="obsolete">Hautatutakoan, aplikazioak ikur bat hornituko du hitzinguru menuarekin sistema erretiluan.</translation>
- </message>
- <message>
- <source>&Show System Tray Icon</source>
- <translation type="obsolete">&Erakutsi Sistema Erretilu Ikurra</translation>
- </message>
- <message>
- <source>&Auto show Dock and Menubar in fullscreen</source>
- <translation type="obsolete">&Berez erakutsi Uztarpen eta Menubarra ikusleiho-osoan</translation>
- </message>
- <message>
- <source>When checked, the host screen saver will be disabled whenever a virtual machine is running.</source>
- <translation type="obsolete">Hautatutakoan, hostalari ikusleiho babeslea ezgaitu egingo da makina birtual bat ekinean badago ere.</translation>
- </message>
- <message>
- <source>Disable Host &ScreenSaver</source>
- <translation type="obsolete">Ezgaitu Hostalari &Ikusleiho-Babeslea</translation>
- </message>
</context>
<context>
<name>UIGlobalSettingsInput</name>
<message>
- <source>Host &Key:</source>
- <translation type="obsolete">Hostalari &Tekla:</translation>
- </message>
- <message>
- <source>Displays the key used as a Host Key in the VM window. Activate the entry field and press a new Host Key. Note that alphanumeric, cursor movement and editing keys cannot be used.</source>
- <translation type="obsolete">Makina Birtualaren leihoan erabilitako Hostalari Tekla erakusten du. Gaitu sarrera eremua eta sakatu Hostalari Tekla berri bat. Ohartu ezin direla erabili hizkizenbakiak, kurtsore mugimenduak eta edizio teklak.</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsInput.ui" line="+24"/>
<source>When checked, the keyboard is automatically captured every time the VM window is activated. When the keyboard is captured, all keystrokes (including system ones like Alt-Tab) are directed to the VM.</source>
<translation>Hautatutakoan, teklatua berezgaitasunez hartzen da Makina Birtualaren leihoa gaitzen den bakoitzean. Teklatua hartzen denan, tekla-sakatze guztiak (sistemaren Alt-Tab bezalakoak barne) MB-era zuzentzen dira.</translation>
@@ -2183,14 +1769,6 @@
<translation>&Berez Hartu Teklatua</translation>
</message>
<message>
- <source>Reset host combination</source>
- <translation type="obsolete">Berrezarri hostalari konbinazioa</translation>
- </message>
- <message>
- <source>Resets the key combination used as the host combination in the VM window.</source>
- <translation type="obsolete">Makina Birtualeko leihoan hostalari konbinazio bezala erabiltako tekla konbinazioa berrezartzen du.</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsInput.cpp" line="+97"/>
<source>Host Key Combination</source>
<translation>Hostalari Tekla Konbinazioa</translation>
@@ -2257,10 +1835,6 @@
<translation>Hizkuntza:</translation>
</message>
<message>
- <source>&Interface Language:</source>
- <translation type="obsolete">&Interfaze Hizkuntza:</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsLanguage.ui" line="+24"/>
<source>&Interface Languages</source>
<translation>&Interfaze Hizkuntzak</translation>
@@ -2299,57 +1873,29 @@
<context>
<name>UIGlobalSettingsNetwork</name>
<message>
- <source>host IPv4 address of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren hostalari IPv4 helbidea okerra da</translation>
- </message>
- <message>
- <source>host IPv4 network mask of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren hostalari IPv4 sare mozorroa okerra da</translation>
- </message>
- <message>
- <source>host IPv6 address of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren hostalari IPv6 helbidea okerra da</translation>
- </message>
- <message>
- <source>DHCP server address of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren DHCP zerbitzari helbidea okerra da</translation>
- </message>
- <message>
- <source>DHCP server network mask of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren DHCP zerbitzari sare mozorroa okerra da</translation>
- </message>
- <message>
- <source>DHCP lower address bound of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren DHCP behe helbide muga okerra da</translation>
- </message>
- <message>
- <source>DHCP upper address bound of <b>%1</b> is wrong</source>
- <translation type="obsolete"><b>%1</b>-ren DHCP goi helbide muga okerra da</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+130"/>
<source>No new name specified for the NAT network previously called <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ez da izen berririk adierazi NAT sarerako, lehengo izena: <b>%1</b> da.</translation>
</message>
<message>
<location line="+10"/>
<source>No CIDR specified for the NAT network <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ez da CIDR adirazi <b>%1</b> NAT sarerako.</translation>
</message>
<message>
<location line="+2"/>
<source>No CIDR specified for the NAT network previously called <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ez da CIDR adierazi NAT sarerako, lehengo izena: <b>%1</b> da.</translation>
</message>
<message>
<location line="+11"/>
<source>Invalid CIDR specified (<i>%1</i>) for the NAT network <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>CIDR baliogabea (<i>%1</i>) adierazi da <b>%2</b> NAT sarearentzat.</translation>
</message>
<message>
<location line="+3"/>
<source>Invalid CIDR specified (<i>%1</i>) for the NAT network previously called <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>CIDR baliogabea (<i>%1</i>) adierazi da NAT sarerako, lehengo izena: <b>%2</b> da.</translation>
</message>
<message>
<location line="+23"/>
@@ -2588,10 +2134,6 @@
<translation>&Editatu hostalaria-bakarrik sarea</translation>
</message>
<message>
- <source>&Host-only Networks:</source>
- <translation type="obsolete">&Hostalaria-bakarrik Sareak:</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsNetwork.ui" line="+22"/>
<source>&NAT Networks</source>
<translation>&NAT Sareak</translation>
@@ -2625,81 +2167,6 @@
</message>
</context>
<context>
- <name>UIGlobalSettingsNetworkDetails</name>
- <message>
- <source>Host-only Network Details</source>
- <translation type="obsolete">Hostalaria-bakarrik Sare Xehetasunak</translation>
- </message>
- <message>
- <source>&Adapter</source>
- <translation type="obsolete">&Egokitzailea</translation>
- </message>
- <message>
- <source>Manual &Configuration</source>
- <translation type="obsolete">Eskuz &Itxurapena</translation>
- </message>
- <message>
- <source>Use manual configuration for this host-only network adapter.</source>
- <translation type="obsolete">Erabili eskuzko itxurapena hostalaria-bakarrik sare egokitzaile honentzat.</translation>
- </message>
- <message>
- <source>&IPv4 Address:</source>
- <translation type="obsolete">&IPv4 Helbidea:</translation>
- </message>
- <message>
- <source>Displays the host IPv4 address for this adapter.</source>
- <translation type="obsolete">Hostalariaren IPv4 helbidea erakusten du egokitzaile honentzat.</translation>
- </message>
- <message>
- <source>IPv4 Network &Mask:</source>
- <translation type="obsolete">IPv4 Sare &Mozorroa:</translation>
- </message>
- <message>
- <source>Displays the host IPv4 network mask for this adapter.</source>
- <translation type="obsolete">Hostalariaren IPv4 sare mozorroa erakusten du egokitzaile honentzat.</translation>
- </message>
- <message>
- <source>I&Pv6 Address:</source>
- <translation type="obsolete">I&Pv6 Helbidea:</translation>
- </message>
- <message>
- <source>Displays the host IPv6 address for this adapter if IPv6 is supported.</source>
- <translation type="obsolete">Hostalariaren IPv6 helbidea erakusten du egokitzaile honentzat IPv6 sostengatzen bada.</translation>
- </message>
- <message>
- <source>IPv6 Network Mask &Length:</source>
- <translation type="obsolete">IPv6 Sare Mozorro &Luzera:</translation>
- </message>
- <message>
- <source>Displays the host IPv6 network mask prefix length for this adapter if IPv6 is supported.</source>
- <translation type="obsolete">Hostalariaren IPv6 sare mozorroa erakusten du egokitzaile honentzat IPv6 sostengatzen bada.</translation>
- </message>
- <message>
- <source>&DHCP Server</source>
- <translation type="obsolete">&DHCP Zerbitzaria</translation>
- </message>
- <message>
- <source>&Enable Server</source>
- <translation type="obsolete">&Gaitu Zerbitzaria</translation>
- </message>
- <message>
- <source>Server Add&ress:</source>
- <translation type="obsolete">Zerbitzari &Helbidea:</translation>
- </message>
- <message>
- <source>Server &Mask:</source>
- <translation type="obsolete">Zerbitzari &Mozorroa:</translation>
- </message>
- <message>
- <source>&Lower Address Bound:</source>
- <translation type="obsolete">&Behe Helbide Muga:</translation>
- </message>
- <message>
- <source>&Upper Address Bound:</source>
- <translation type="obsolete">&Goi Helbide Muga:</translation>
- </message>
-</context>
-<context>
<name>UIGlobalSettingsNetworkDetailsHost</name>
<message>
<location filename="../src/settings/global/UIGlobalSettingsNetworkDetailsHost.ui" line="+26"/>
@@ -2729,7 +2196,7 @@
<message>
<location line="+19"/>
<source>Holds the host IPv4 address for this adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalariaren IPv4 helbidea zehazten du egokitzaile honentzat.</translation>
</message>
<message>
<location line="+7"/>
@@ -2739,7 +2206,7 @@
<message>
<location line="+19"/>
<source>Holds the host IPv4 network mask for this adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalariaren IPv4 sare mozorroa zehazten du egokitzaile honentzat.</translation>
</message>
<message>
<location line="+7"/>
@@ -2749,7 +2216,7 @@
<message>
<location line="+19"/>
<source>Holds the host IPv6 address for this adapter if IPv6 is supported.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalariaren IPv6 helbidea zehazten du egokitzaile honentzat IPv6 sostengatzen bada.</translation>
</message>
<message>
<location line="+7"/>
@@ -2759,7 +2226,7 @@
<message>
<location line="+19"/>
<source>Holds the host IPv6 network mask prefix length for this adapter if IPv6 is supported.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalariaren IPv6 sare mozorro aurrizki luzera zehazten du egokitzaile honentzat IPv6 sostengatzen bada.</translation>
</message>
<message>
<location line="+21"/>
@@ -2774,7 +2241,7 @@
<message>
<location line="+3"/>
<source>Indicates whether the DHCP Server is enabled on machine startup or not.</source>
- <translation type="unfinished"></translation>
+ <translation>DHCP zerbitzaria makina abiarazterakoan gaitzen den edo ez adierazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2784,7 +2251,7 @@
<message>
<location line="+19"/>
<source>Holds the address of the DHCP server servicing the network associated with this host-only adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalaria-bakarrik egokitzailearekin elkartutako sarea zerbitzatzen duen DHCP zerbitzariaren helbidea zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2794,7 +2261,7 @@
<message>
<location line="+19"/>
<source>Holds the network mask of the DHCP server servicing the network associated with this host-only adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalaria-bakarrik egokitzailearekin elkartutako sarea zerbitzatzen duen DHCP zerbitzariak eskaintzen duen sare mozorroa erakusten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2804,7 +2271,7 @@
<message>
<location line="+19"/>
<source>Holds the lower address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalaria-bakarrik egokitzailearekin elkartutako sarea zerbitzatzen duen DHCP zerbitzariak eskaintzen duen beheren helbide muga zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2814,7 +2281,7 @@
<message>
<location line="+19"/>
<source>Holds the upper address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
- <translation type="unfinished"></translation>
+ <translation>Hostalaria-bakarrik egokitzailearekin elkartutako sarea zerbitzatzen duen DHCP zerbitzariak eskaintzen duen goren helbide muga erakusten du.</translation>
</message>
</context>
<context>
@@ -2842,7 +2309,7 @@
<message>
<location line="+13"/>
<source>Holds the name for this network.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare honen izena zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2852,7 +2319,7 @@
<message>
<location line="+13"/>
<source>Holds the CIDR for this network.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare honentzako CIDR-a zehazten du.</translation>
</message>
<message>
<location line="+10"/>
@@ -2867,7 +2334,7 @@
<message>
<location line="+3"/>
<source>Determines whether this network supports DHCP.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare honek DHCP sostengatzen duen zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2877,17 +2344,17 @@
<message>
<location line="+3"/>
<source>Determines whether this network supports IPv6.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare honek IPv6 sostengatzen duen zehazten du.</translation>
</message>
<message>
<location line="+7"/>
<source>Advertise Default IPv6 &Route</source>
- <translation type="unfinished"></translation>
+ <translation>Iragarri Berezko IP&v6 biderapena</translation>
</message>
<message>
<location line="+3"/>
<source>Determines whether this network should be advertised as the default IPv6 route.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare hau berezko IPv6 biderapen bezala iragarri behar den zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -2923,11 +2390,7 @@
<message>
<location filename="../src/settings/global/UIGlobalSettingsProxy.ui" line="+24"/>
<source>When checked, VirtualBox will use the proxy settings supplied for tasks like downloading Guest Additions from the network or checking for updates.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>&Enable proxy</source>
- <translation type="obsolete">&Gaitu proxya</translation>
+ <translation>Hautatutakoan, VirtualBox-ek proxy ezarpenak erabiliko ditu Gonbidatu Gehigarriak saretik jeisteko edo eguneraketak egiaztatzeko bezalako eginkizunetarako.</translation>
</message>
<message>
<location line="+3"/>
@@ -2955,26 +2418,6 @@
<translation>Proxy ataka aldatzen du.</translation>
</message>
<message>
- <source>&Use authentication</source>
- <translation type="obsolete">&Erabili egiaztapena</translation>
- </message>
- <message>
- <source>User &name:</source>
- <translation type="obsolete">&Erabiltzaile izena:</translation>
- </message>
- <message>
- <source>Changes the user name used for authentication.</source>
- <translation type="obsolete">Egiaztapenerako erabilitako erabiltzaile izena aldatzen du.</translation>
- </message>
- <message>
- <source>Pass&word:</source>
- <translation type="obsolete">&Sarhitza:</translation>
- </message>
- <message>
- <source>Changes the password used for authentication.</source>
- <translation type="obsolete">Egiaztapenerako erabilitako sarhitza aldatzen du.</translation>
- </message>
- <message>
<location filename="../src/settings/global/UIGlobalSettingsProxy.cpp" line="+121"/>
<source>No proxy host is currently specified.</source>
<translation>Ez dago proxy hostalaririk adierazita.</translation>
@@ -2990,11 +2433,7 @@
<message>
<location filename="../src/settings/global/UIGlobalSettingsUpdate.ui" line="+24"/>
<source>When checked, the application will periodically connect to the VirtualBox website and check whether a new VirtualBox version is available.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>&Check for updates</source>
- <translation type="obsolete">&Egiaztatu eguneraketak</translation>
+ <translation>Hautatutakoan, aplikazioa aldika VirtualBox webgunera elkartuko da eta VirtualBox bertsio berri bat eskuragarri dagoen egiaztatuko du.</translation>
</message>
<message>
<location line="+3"/>
@@ -3009,7 +2448,7 @@
<message>
<location line="+15"/>
<source>Specifies how often the new version check should be performed. Note that if you want to completely disable this check, just clear the above check box.</source>
- <translation type="unfinished"></translation>
+ <translation>Bertsio berri egiaztapena zein maiz egin behar den hautatzen du. Ohartu egiaztapen hau erabat ezgaitzea nahi baduzu, garbitu gaineko hauta-kutxatila.</translation>
</message>
<message>
<location line="+28"/>
@@ -3034,16 +2473,12 @@
<message>
<location line="+10"/>
<source>&All New Releases</source>
- <translation>Argitalpen &Berri Guztiak</translation>
+ <translation>Argitalpen Berri &Guztiak</translation>
</message>
<message>
<location line="+10"/>
<source>All New Releases and &Pre-Releases</source>
- <translation>Argitalpen Berri eta &Aurre-Argitapen Guztiak</translation>
- </message>
- <message>
- <source>&Stable release versions</source>
- <translation type="obsolete">&Bertsio egonkor agirtalpenak</translation>
+ <translation>Argitalpen Berri eta A&urre-Argitapen Guztiak</translation>
</message>
<message>
<location line="-13"/>
@@ -3051,18 +2486,10 @@
<translation><p>Hautatu hau VirtualBox argitalpen berri guztien jakinarazpena jasotzea nahi baduzu.</p></translation>
</message>
<message>
- <source>&All new releases</source>
- <translation type="obsolete">&Argitalpen berri guztiak</translation>
- </message>
- <message>
<location line="+10"/>
<source><p>Choose this to be notified about all new VirtualBox releases and pre-release versions of VirtualBox.</p></source>
<translation><p>Hautatu hau VirtualBox argitalpen eta aurre-argitalpen berri guztien jakinarazpena jasotzea nahi baduzu.</p></translation>
</message>
- <message>
- <source>All new releases and &pre-releases</source>
- <translation type="obsolete">&Argitalpen berri eta aurre-argitalpen guztiak</translation>
- </message>
</context>
<context>
<name>UIHelpButton</name>
@@ -3153,7 +2580,7 @@
<message>
<location line="+17"/>
<source>Host+</source>
- <translation>Host+</translation>
+ <translation>Hostalaria+</translation>
</message>
<message>
<location line="+15"/>
@@ -3165,70 +2592,6 @@
<context>
<name>UIHotKeyEditor</name>
<message>
- <source>Left </source>
- <translation type="obsolete">Ezker </translation>
- </message>
- <message>
- <source>Right </source>
- <translation type="obsolete">Eskuin </translation>
- </message>
- <message>
- <source>Right Alt</source>
- <translation type="obsolete">Eskuineko Alt</translation>
- </message>
- <message>
- <source>Left WinKey</source>
- <translation type="obsolete">Ezker Win-Tekla</translation>
- </message>
- <message>
- <source>Right WinKey</source>
- <translation type="obsolete">Eskuineko Win-Tekla</translation>
- </message>
- <message>
- <source>Menu key</source>
- <translation type="obsolete">Menu tekla</translation>
- </message>
- <message>
- <source>Alt Gr</source>
- <translation type="obsolete">Alt Gr</translation>
- </message>
- <message>
- <source>Caps Lock</source>
- <translation type="obsolete">Larri Blokeoa</translation>
- </message>
- <message>
- <source>Scroll Lock</source>
- <translation type="obsolete">Irristari Blokeoa</translation>
- </message>
- <message>
- <source><key_%1></source>
- <translation type="obsolete"><key_%1></translation>
- </message>
- <message>
- <source>None</source>
- <translation type="obsolete">Ezer ez</translation>
- </message>
- <message>
- <source>Left Shift</source>
- <translation type="obsolete">Ezker Aldatu</translation>
- </message>
- <message>
- <source>Right Shift</source>
- <translation type="obsolete">Eskuineko Aldatu</translation>
- </message>
- <message>
- <source>Left Ctrl</source>
- <translation type="obsolete">Ezker Ktrl</translation>
- </message>
- <message>
- <source>Right Ctrl</source>
- <translation type="obsolete">Eskuineko Ktrl</translation>
- </message>
- <message>
- <source>Left Alt</source>
- <translation type="obsolete">Ezker Alt</translation>
- </message>
- <message>
<location line="-366"/>
<location filename="../src/widgets/UIHotKeyEditor.cpp" line="+173"/>
<source>Unset shortcut</source>
@@ -3258,7 +2621,7 @@
<message>
<location filename="../src/wizards/importappliance/UIWizardImportApp.cpp" line="+117"/>
<source><b>The virtual system "%1" requires that you agree to the terms and conditions of the software license agreement shown below.</b><br /><br />Click <b>Agree</b> to continue or click <b>Disagree</b> to cancel the import.</source>
- <translation type="unfinished"></translation>
+ <translation><b>"%1" sistema birtualak azpian erakusten den software baimen itunaren neurriak eta baldintzak onartzea behar du.</b><br /><br />Klikatu <b>Onartu</b> jarraitzeko edo klikatu <b>Baztertu</b> inportazioa ezeztatzeko.</translation>
</message>
<message>
<location line="-2"/>
@@ -3395,7 +2758,7 @@
<location line="+123"/>
<source>Additional feature status:<br><nobr><b>%1:</b> %2</nobr><br><nobr><b>%3:</b> %4</nobr><br><nobr><b>%5:</b> %6</nobr><br><nobr><b>%7:</b> %8%</nobr></source>
<comment>Virtualization Stuff LED</comment>
- <translation type="unfinished"></translation>
+ <translation>Ezaugarri gehigarriaren egoera:<br><nobr><b>%1:</b> %2</nobr><br><nobr><b>%3:</b> %4</nobr><br><nobr><b>%5:</b> %6</nobr><br><nobr><b>%7:</b> %8%</nobr></translation>
</message>
<message>
<location line="+14"/>
@@ -3406,16 +2769,12 @@
<message>
<location line="+33"/>
<source>Indicates whether the host mouse pointer is captured by the guest OS:<br><nobr><img src=:/mouse_disabled_16px.png/> pointer is not captured</nobr><br><nobr><img src=:/mouse_16px.png/> pointer is captured</nobr><br><nobr><img src=:/mouse_seamless_16px.png/> mouse integration (MI) is On</nobr><br><nobr><img src=:/mouse_can_seamless_ [...]
- <translation type="unfinished"></translation>
+ <translation>SE gonbidatuak hostalari saguaren punta nola hartzen duen adierazten du:<br><nobr><img src=:/mouse_disabled_16px.png/> punta ez da hartzen</nobr><br><nobr><img src=:/mouse_16px.png/> punta hartzen da</nobr><br><nobr><img src=:/mouse_seamless_16px.png/> sagu baterapena (SB) Piztuta dago</nobr><br><nobr><img src=:/mouse_can_sea [...]
</message>
<message>
<location line="+50"/>
<source>Indicates whether the keyboard is captured by the guest OS (<img src=:/hostkey_captured_16px.png/>) or not (<img src=:/hostkey_16px.png/>).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><hr>The Remote Desktop Server is listening on port %1</source>
- <translation type="obsolete"><hr>Hurruneko Mahaigain Zerbitzaria %1 atakan ari da aditzen</translation>
+ <translation>Teklatua gonbidatu SE-k hartzen duen zehazten du (<img src=:/hostkey_captured_16px.png/>) or not (<img src=:/hostkey_16px.png/>).</translation>
</message>
</context>
<context>
@@ -3459,22 +2818,6 @@
<translation>Elkarketatu %1 Sare Egokitzailea</translation>
</message>
<message>
- <source>No CD/DVD Devices Attached</source>
- <translation type="obsolete">Ez da CD/DVD Gailurik Erantsi</translation>
- </message>
- <message>
- <source>No CD/DVD devices attached to that VM</source>
- <translation type="obsolete">Ez da CD/DVD Gailurik Erantsi MB horretara</translation>
- </message>
- <message>
- <source>No Floppy Devices Attached</source>
- <translation type="obsolete">Ez da Diskete Gailurik Erantsi</translation>
- </message>
- <message>
- <source>No floppy devices attached to that VM</source>
- <translation type="obsolete">Ez da Diskete Gailurik Erantsi MB horretara</translation>
- </message>
- <message>
<location line="-292"/>
<source>No USB Devices Connected</source>
<translation>Ez da USB Gailurik Erantsi</translation>
@@ -3495,7 +2838,7 @@
<message>
<location filename="../src/settings/machine/UIMachineSettingsAudio.ui" line="+24"/>
<source>When checked, a virtual PCI audio card will be plugged into the virtual machine and will communicate with the host audio system using the specified driver.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, PCI audio txartel birtual bat txertatuko da makina birtualean eta hostalariaren audio sistemarekin komunikatuko da adierazitako gidatzailea erabiliz.</translation>
</message>
<message>
<location line="+3"/>
@@ -3505,17 +2848,17 @@
<message>
<location line="+29"/>
<source>Host Audio &Driver:</source>
- <translation>Hostalariko Audio &Gidagailua:</translation>
+ <translation>&Hostalariko Audio Gidagailua:</translation>
</message>
<message>
<location line="+19"/>
<source>Controls the audio output driver. The <b>Null Audio Driver</b> makes the guest see an audio card, however every access to it will be ignored.</source>
- <translation type="unfinished"></translation>
+ <translation>Audio irteera gidatzailea agintzen du. <b>Null Audio Gidatzailea</b>k gonbidatuak audio txartel bat ikustea egiten du, horrela ere bertarako sarbidea ezikusi egingo da.</translation>
</message>
<message>
<location line="+7"/>
<source>Audio &Controller:</source>
- <translation>Audio &Kontrolatzailea:</translation>
+ <translation>&Audio Kontrolatzailea:</translation>
</message>
<message>
<location line="+19"/>
@@ -3528,42 +2871,42 @@
<message>
<location filename="../src/settings/machine/UIMachineSettingsDisplay.cpp" line="+322"/>
<source>The virtual machine is set up to use hardware graphics acceleration. However the host system does not currently provide this, so you will not be able to start the machine.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtual hau hardware bizkorpena erabiltzeko ezarrita dago Horrela ere hostalari sistemak ezin du oraingoz hau hornitu, hortaz ez zara makina abiarazeko gai izango.</translation>
</message>
<message>
<location line="+13"/>
<source>The virtual machine is currently assigned less than <b>%1</b> of video memory which is the minimum amount required to switch to fullscreen or seamless mode.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualak une honetan ikusleiho-osoko edo irudizko modura aldatzeko behar den bideo oroimen kopuru gutxiena baino <b>%1</b> gutxiago du esleituta.</translation>
</message>
<message>
<location line="+11"/>
<source>The virtual machine is currently assigned less than <b>%1</b> of video memory which is the minimum amount required for High Definition Video to be played efficiently.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualak une honetan Bereizmen Handiko Bideoa eraginkortasunez irakurria izateko behar den kopuru gutxiena baino <b>%1</b> bideo oroimen gutxiago du esleituta.</translation>
</message>
<message>
<location line="+17"/>
<source>The virtual machine is set up to use hardware graphics acceleration and the operating system hint is set to Windows Vista or later. For best performance you should set the machine's video memory to at least b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtuala hardware grafiko bizkorpena erabiltzeko ezarrita dago eta sistema eragilea Windows Vista edo berriagoan zehaztua dago. Egintza hoberenearako makinaren bideo oroimena gutxienez <b>%1</b> balioan ezarri behar duzu.</translation>
</message>
<message>
<location line="+14"/>
<source>The virtual machine is set up to use Video Stream Acceleration. As this feature only works with Windows guest systems it will be disabled.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtuala Bideo Jario Bizkorpena erabiltzeko ezarrita dago. Ezaugarri honek Windows gonbidatu sistemekin besterik lan egiten ez duenez ezgaitua izango da.</translation>
</message>
<message>
<location line="+20"/>
<source>Remote Display is currently enabled for this virtual machine. However, this requires the <b>%1</b> to be installed. Please install the Extension Pack from the VirtualBox download site as otherwise your VM will be started with Remote Display disabled.</source>
- <translation type="unfinished"></translation>
+ <translation>Hurruneko Erakuspena une honetan gaituta dago makina birtual honentzat. Horrela ere, honek <i>%1</i> ezarrita behar du. Mesedez ezarri Hedapen Paketea VirtualBox jeisketa gunetik bestela zure MB Hurruneko Erakuspen ezgaituta duela abiatuko da.</translation>
</message>
<message>
<location line="+11"/>
<source>The VRDE server port value is not currently specified.</source>
- <translation type="unfinished"></translation>
+ <translation>VRDE zerbitzari ataka balioa ez dago adierazita.</translation>
</message>
<message>
<location line="+7"/>
<source>The VRDE authentication timeout value is not currently specified.</source>
- <translation type="unfinished"></translation>
+ <translation>VRDE egiaztapen epea balioa ez dago adierazita.</translation>
</message>
<message>
<location line="+54"/>
@@ -3651,12 +2994,12 @@
<message>
<location line="+40"/>
<source>&Remote Display</source>
- <translation>&Hurruneko Erakuspena</translation>
+ <translation>Hurruneko &Erakuspena</translation>
</message>
<message>
<location line="+9"/>
<source>When checked, the VM will act as a Remote Desktop Protocol (RDP) server, allowing remote clients to connect and operate the VM (when it is running) using a standard RDP client.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, MB-k Hurruneko Mahaigain Protokolo (RDP) zerbitzari bat bezala jokatuko du, hurruneko bezeroei MB-ra (ekinean dagoenean) elkartzea eta eragiketak egitea ahalbidetuz RDP bezero estandarra erabiliz.</translation>
</message>
<message>
<location line="+3"/>
@@ -3691,7 +3034,7 @@
<message>
<location line="+53"/>
<source>Video &Capture</source>
- <translation>Bideo &Harpena</translation>
+ <translation>&Bideo Harpena</translation>
</message>
<message>
<location line="+12"/>
@@ -3820,10 +3163,6 @@
<context>
<name>UIMachineSettingsGeneral</name>
<message>
- <source>Displays the path where snapshots of this virtual machine will be stored. Be aware that snapshots can take quite a lot of disk space.</source>
- <translation type="obsolete">Makina birtual honen berehalakoak gordetzen diren helburua erakusten du. Ohartarazten dugu argazkiek diskako tokia asko hartzen dutela.</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsGeneral.ui" line="+33"/>
<source>&Basic</source>
<translation>&Ohinarrizkoa</translation>
@@ -3841,7 +3180,7 @@
<message>
<location line="+19"/>
<source>Selects which clipboard data will be copied between the guest and the host OS. This feature requires Guest Additions to be installed in the guest OS.</source>
- <translation type="unfinished"></translation>
+ <translation>Gonbidatuaren eta hostalari SE-ren artean gakoko zein datu kopiatuko diren hautatzen du. Ezaugarri honek gonbidatu SE-n Gonbidatu Gehigarriak ezarrita behar ditu.</translation>
</message>
<message>
<location line="-42"/>
@@ -3864,10 +3203,6 @@
<translation>&Azalpena</translation>
</message>
<message>
- <source>Displays the description of the virtual machine. The description field is useful for commenting on configuration details of the installed guest OS.</source>
- <translation type="obsolete">Makina birtualaren azalpena erakusten du. Azalpen eramua erabilgarria da ezarritako SE gonbidatuaren itxurapen xehetasunak aipatzeko.</translation>
- </message>
- <message>
<location line="-94"/>
<source>Removable Media:</source>
<translation>Multimedia Kengarria:</translation>
@@ -3875,7 +3210,7 @@
<message>
<location line="+16"/>
<source>If checked, any CD/DVD or floppy disks inserted into or removed from the virtual drives while the machine is running will be remembered.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatzen bada, makina jardunean dagoen bitartean gidagailu birtuletan txertatzen den edo kentzen den edozein CD/DVD edo diskete gogoratu egingo da.</translation>
</message>
<message>
<location line="+3"/>
@@ -3895,20 +3230,12 @@
<message>
<location line="+58"/>
<source>Holds the description of the virtual machine. The description field is useful for commenting on configuration details of the installed guest OS.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Show In &Fullscreen/Seamless</source>
- <translation type="obsolete">Erakutsi &Ikusleiho-osoan/Irudizkoan</translation>
+ <translation>Makina birtualaren azalpen zehazten du. Azalpen eremu hau erabilgarria da ezarritako gonbidatu SE-ren itxurapen xehetasunen aipamenak egiteko.</translation>
</message>
<message>
<location line="-39"/>
<source>If checked, show the Mini ToolBar at the top of the screen, rather than in its default position at the bottom of the screen.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Show At &Top Of Screen</source>
- <translation type="obsolete">&Erakutsi Ikusleihoaren Goialdean</translation>
+ <translation>Hautatzen bada, Tresna-Barra Txikia erakusten du ikusleiho-osoaren goialdean, berezko ikusleihoaren behealdearen ordez.</translation>
</message>
<message>
<location line="-103"/>
@@ -3928,12 +3255,12 @@
<message>
<location line="+7"/>
<source>The virtual machine operating system hint is set to a 64-bit type. 64-bit guest systems require hardware virtualization, so this will be enabled automatically if you confirm the changes.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualaren sistema eragilea 64-bit motakoan ezarrita dago. 64-biteko gonbidatu sistemek hardware birtualizazioa behar dute, hortaz hau berezgaitasunez gaituko da aldaketak baieztatzen badituzu.</translation>
</message>
<message>
<location line="+37"/>
<source>Holds the path where snapshots of this virtual machine will be stored. Be aware that snapshots can take quite a lot of disk space.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtual honen berehalakoak biltegiratuko diren helburua zehazten du. Kontuz ibili berehalakoak diskako toki asko hartu dezakeelako.</translation>
</message>
</context>
<context>
@@ -3966,19 +3293,7 @@
<message>
<location line="+60"/>
<source>Adapter &Type:</source>
- <translation>Egokitzaile &Mota:</translation>
- </message>
- <message>
- <source>no bridged network adapter is selected</source>
- <translation type="obsolete">ez da zubitutako sare egokitzailerik hautatu</translation>
- </message>
- <message>
- <source>no internal network name is specified</source>
- <translation type="obsolete">ez da barneko sare izenik adierazi</translation>
- </message>
- <message>
- <source>no host-only network adapter is selected</source>
- <translation type="obsolete">ez da hostalaria-bakarrik sare egokitzailerik hautatu</translation>
+ <translation>&Egokitzaile Mota:</translation>
</message>
<message>
<location filename="../src/settings/machine/UIMachineSettingsNetwork.cpp" line="+718"/>
@@ -4003,10 +3318,6 @@
<translation>Sare gehigarri egokitzaile aukerak erakutsi edo ezkutatzen ditu.</translation>
</message>
<message>
- <source>Displays the MAC address of this adapter. It contains exactly 12 characters chosen from {0-9,A-F}. Note that the second character must be an even digit.</source>
- <translation type="obsolete">Egokitzaile honen MAC helbidea erakusten du. Zehatz-mehatz 12 hizki ditu {0-9,A-F}-tik hartuta. Ohartu bigarren hizkia zenbaki bikoiti bat izan behar dela.</translation>
- </message>
- <message>
<location line="+87"/>
<source>Generates a new random MAC address.</source>
<translation>Zorizko MAC helbide berri bat sortzen du.</translation>
@@ -4017,14 +3328,6 @@
<translation>Abiaraztean sare birtual kablea makinara elkartuta egongo den edo ez adierazten du.</translation>
</message>
<message>
- <source>&Cable connected</source>
- <translation type="obsolete">&Kablea elkartuta</translation>
- </message>
- <message>
- <source>Opens dialog to manage port forwarding rules.</source>
- <translation type="obsolete">Bidalketa ataka arau kudeaketarako elkarrizketa irekitzen du.</translation>
- </message>
- <message>
<location line="+13"/>
<source>&Port Forwarding</source>
<translation>&Bidalketa Ataka</translation>
@@ -4032,17 +3335,17 @@
<message>
<location line="-96"/>
<source>&Promiscuous Mode:</source>
- <translation type="unfinished"></translation>
+ <translation>&Promiskuo Modua:</translation>
</message>
<message>
<location line="+19"/>
<source>Selects the promiscuous mode policy of the network adapter when attached to an internal network, host only network or a bridge.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare egokitzailearen modu promiskuoa hautatzen du barneko sare batera, hostalaria bakarrik sare batera edo zubi batera erantsita dagoenean.</translation>
</message>
<message>
<location line="+26"/>
<source>Holds the MAC address of this adapter. It contains exactly 12 characters chosen from {0-9,A-F}. Note that the second character must be an even digit.</source>
- <translation type="unfinished"></translation>
+ <translation>Egokitzaile honen MAC helbidea zehazten du. Zehatz-mehatz 12 hizki ditu {0-9,A-F}-tik hartuta. Ohartu bigarren hizkia zenbaki bikoiti bat izan behar dela.</translation>
</message>
<message>
<location line="+21"/>
@@ -4052,7 +3355,7 @@
<message>
<location line="+10"/>
<source>Enter any configuration settings here for the network attachment driver you will be using. The settings should be of the form <b>name=value</b> and will depend on the driver. Use <b>shift-enter</b> to add a new entry.</source>
- <translation type="unfinished"></translation>
+ <translation>Sartu hemen erabiliko duzun sare eranspen gidagailuaren itxurapen ezarpenak. Ezarpenak <b>izena=balioa</b> forman izan behar dira eta gidagailuaren mendekoak izango dira. Erabili<b>aldatu-sartu</b> sarrera berri bat gehitzeko.</translation>
</message>
<message>
<location line="+10"/>
@@ -4065,13 +3368,9 @@
<translation>Bidalketa ataka arauak kudeatzeko leiho bat irekitzen du.</translation>
</message>
<message>
- <source>no generic driver is selected</source>
- <translation type="obsolete">ez da gidatzaile generikorik hautatu</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsNetwork.cpp" line="-310"/>
<source>Selects the network adapter on the host system that traffic to and from this network card will go through.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare txartel honetara eta honetatik igaroko den trafikoa hostalari sistemako sare egokitzailea hautatzen du.</translation>
</message>
<message>
<location line="-220"/>
@@ -4106,17 +3405,17 @@
<message>
<location line="+10"/>
<source>The second digit in the MAC address may not be odd as only unicast addresses are allowed.</source>
- <translation type="unfinished"></translation>
+ <translation>MAC helbideko bigarren digitoa badaiteke arraroa ez izatea unicast helbideak bakarrik ahalbidetzen direlako.</translation>
</message>
<message>
<location line="+169"/>
<source>Holds the name of the internal network that this network card will be connected to. You can create a new internal network by choosing a name which is not used by any other network cards in this virtual machine or others.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare txartel hau elkartuko den barneko sarearen izena zehazten du. Barneko sare berri bat sortu dezakezu makina birtual honetan edo beste batean beste sare txartelek erabiltzen ez duten izen bat hautatuz.</translation>
</message>
<message>
<location line="+9"/>
<source>Selects the virtual network adapter on the host system that traffic to and from this network card will go through. You can create and remove adapters using the global network settings in the virtual machine manager window.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare txartel honetara eta honetatik igaroko den trafikoa hostalari sistemako sare egokitzailea hautatzen du. Egokitzaileak sortu eta kendu ditzakezu sare ezarpen orokorrak erabiliz makina birtualaren kudeatzaile leihoan.</translation>
</message>
<message>
<location line="+9"/>
@@ -4126,17 +3425,13 @@
<message>
<location line="+6"/>
<source>Holds the name of the NAT network that this network card will be connected to. You can create and remove networks using the global network settings in the virtual machine manager window.</source>
- <translation type="unfinished"></translation>
+ <translation>Sare txartel hau elkartzen den NAT sarearen izena zehazten du. Sareak sortu eta kendu ditzakezu sare ezarpen orokorrak erabiliz makina birtual kudeatzailearen leihoan.</translation>
</message>
<message>
<location filename="../src/settings/machine/UIMachineSettingsNetwork.ui" line="-67"/>
<source>&MAC Address:</source>
<translation>&MAC Helbidea:</translation>
</message>
- <message>
- <source>the MAC address must be 12 hexadecimal digits long.</source>
- <translation type="obsolete">MAC helbideak 12 digito hexadezimaleko luzera izan behar du.</translation>
- </message>
</context>
<context>
<name>UIMachineSettingsParallel</name>
@@ -4164,7 +3459,7 @@
<message>
<location line="+13"/>
<source>Holds the parallel port number. You can choose one of the standard parallel ports or select <b>User-defined</b> and specify port parameters manually.</source>
- <translation type="unfinished"></translation>
+ <translation>Ataka paralelo zenbakia zehazten du. Ataka paraleko estandar bat hautatu dezakezu edo hautatu <b>Erabiltzaileak-zehaztuta</b> eta adierazi ataka parametroak eskuz.</translation>
</message>
<message>
<location line="+7"/>
@@ -4174,17 +3469,17 @@
<message>
<location line="+16"/>
<source>Holds the IRQ number of this parallel port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
- <translation type="unfinished"></translation>
+ <translation>Ataka paralelo honen IRQ zenbakia zehazten du. Hau <tt>0</tt> eta <tt>255</tt> arteko zenbaki oso bat izan behar da. <tt>15</tt> baino balio handiagoak makina birtual honentzat <b>I/O APIC</b> ezarpena gaituta badago bakarrik erabili daitezke.</translation>
</message>
<message>
<location line="+7"/>
<source>I/O Po&rt:</source>
- <translation>S/I &Ataka:</translation>
+ <translation>&S/I Ataka:</translation>
</message>
<message>
<location line="+16"/>
<source>Holds the base I/O port address of this parallel port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ataka paralelo honen ohinarri S/I ataka helbideak zehazten ditu. Baliozko balioak <tt>0</tt> eta <tt>0xFFFF</tt> arteko zenbaki osoak dira.</translation>
</message>
<message>
<location line="+7"/>
@@ -4194,28 +3489,12 @@
<message>
<location line="+13"/>
<source>Holds the host parallel device name.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Displays the host parallel device name.</source>
- <translation type="obsolete">Hostalari gailu kidetu izena erakusten du.</translation>
+ <translation>Hostalari paraleloaren gailu izena zehazten du.</translation>
</message>
</context>
<context>
<name>UIMachineSettingsParallelPage</name>
<message>
- <source>Duplicate port number selected </source>
- <translation type="obsolete">Bikoiztu hautaturiko ataka zenbakia </translation>
- </message>
- <message>
- <source>Port path not specified </source>
- <translation type="obsolete">Ataka helburua ez da adierazi </translation>
- </message>
- <message>
- <source>Duplicate port path entered </source>
- <translation type="obsolete">Bikoiztu sartutako ataka helburua </translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsParallel.cpp" line="+227"/>
<source>No IRQ is currently specified.</source>
<translation>Ez dago IRQ-rik adierazita.</translation>
@@ -4304,7 +3583,7 @@
<message>
<location line="+3"/>
<source> Transient Folders</source>
- <translation type="unfinished"></translation>
+ <translation> Aldaketa giritegiak</translation>
</message>
<message>
<location line="-273"/>
@@ -4319,7 +3598,7 @@
<message>
<location filename="../src/settings/machine/UIMachineSettingsSF.ui" line="+69"/>
<source>Lists all shared folders accessible to this machine. Use 'net use x: \\vboxsvr\share' to access a shared folder named <i>share</i> from a DOS-like OS, or 'mount -t vboxsf share mount_point' to access it from a Linux OS. This feature requires Guest Additions.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina honetatik eskuragarri dauden elkarbanatutako agiritegi guztiak zerrendatzen ditu. Erabili 'net use x: \\vboxsvr\share' <i>share</i> izeneko elkarbanatutako agiritegi batera sarbidea izateko, edo 'mount -t vboxsf share mount_point' Linux SE batetik sarbidea izateko. Ezaugarri honek Gonbidatu Gehigarriak behar ditu.</translation>
</message>
<message>
<location line="+10"/>
@@ -4362,10 +3641,6 @@
<translation>&Agiritegia Zerrenda</translation>
</message>
<message>
- <source>Auto-Mount</source>
- <translation type="obsolete">Berez-Osatu</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsSF.cpp" line="+15"/>
<source>Yes</source>
<translation>Bai</translation>
@@ -4384,10 +3659,6 @@
<translation>Editatu Elkarbanaketa</translation>
</message>
<message>
- <source>Dialog</source>
- <translation type="obsolete">Elkarrizketa</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsSFDetails.ui" line="+32"/>
<source>Folder Path:</source>
<translation>Agiritegi Helburua:</translation>
@@ -4398,10 +3669,6 @@
<translation>Agiritegi Izena:</translation>
</message>
<message>
- <source>Displays the name of the shared folder (as it will be seen by the guest OS).</source>
- <translation type="obsolete">Elkarbanatutako agiritegiaren izena erakusten du (Gonbidatu SE-n ikusiko den bezala).</translation>
- </message>
- <message>
<location line="+17"/>
<source>When checked, the guest OS will not be able to write to the specified shared folder.</source>
<translation>Hautatzen bada, gonbidatu SE-ak ezingo du adierazitako agiritegi elkarbanatuan idatzi.</translation>
@@ -4429,7 +3696,7 @@
<message>
<location line="+29"/>
<source>Holds the name of the shared folder (as it will be seen by the guest OS).</source>
- <translation type="unfinished"></translation>
+ <translation>Elkarbanatutako agiritegiaren izena zehazten du (gonbidatu SE-k ikusiko duen bezala).</translation>
</message>
<message>
<location line="+20"/>
@@ -4463,16 +3730,12 @@
<message>
<location line="+41"/>
<source>Port &Number:</source>
- <translation>&Ataka Zenbakia:</translation>
- </message>
- <message>
- <source>Displays the serial port number. You can choose one of the standard serial ports or select <b>User-defined</b> and specify port parameters manually.</source>
- <translation type="obsolete">Serieko ataka zenbakia erakusten du. Serieko ataka estandar bat hautatu dezakezu edo hautatu <b>Erabiltzaileak-zehaztuta</b> eta adierazi ataka parametroak eskuz.</translation>
+ <translation>Ataka &Zenbakia:</translation>
</message>
<message>
<location line="+13"/>
<source>Selects the serial port number. You can choose one of the standard serial ports or select <b>User-defined</b> and specify port parameters manually.</source>
- <translation type="unfinished"></translation>
+ <translation>Serie ataka zenbakia erakusten du. Serieko taka estandar bat hautatu dezakezu edo hautatu <b>Erabiltzaileak-zehaztuta</b> eta adierazi ataka parametroak eskuz.</translation>
</message>
<message>
<location line="+7"/>
@@ -4482,7 +3745,7 @@
<message>
<location line="+10"/>
<source>Holds the IRQ number of this serial port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
- <translation type="unfinished"></translation>
+ <translation>Serie ataka honen IRQ zenbakia zehazten du. Hau <tt>0</tt> eta <tt>255</tt> arteko zenbaki oso bat izan behar da. <tt>15</tt> baino balio handiagoak makina birtual honentzat <b>I/O APIC</b> ezarpena gaituta badago bakarrik erabili daitezke.</translation>
</message>
<message>
<location line="+7"/>
@@ -4492,7 +3755,7 @@
<message>
<location line="+10"/>
<source>Holds the base I/O port address of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
- <translation type="unfinished"></translation>
+ <translation>Serieko ataka honen ohinarri S/I ataka helbidea zehazten du. Baliozko balioak <tt>0</tt> eta <tt>0xFFFF</tt> arteko zenbaki osoak dira.</translation>
</message>
<message>
<location line="+26"/>
@@ -4507,7 +3770,7 @@
<message>
<location line="+20"/>
<source>If checked, the pipe specified in the <b>Port Path</b> field will be created by the virtual machine when it starts. Otherwise, the virtual machine will assume that the pipe exists and try to use it.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatzen bada, makina birtualak <b>Ataka Helburua</b> eremuan adierazitako hodia sortuko da makina birtuala abiaraztean. Bestela, makina birtualak hodia jadanik badagoela iritziko dio eta erabiltzen saiatuko da.</translation>
</message>
<message>
<location line="+3"/>
@@ -4517,33 +3780,17 @@
<message>
<location line="+20"/>
<source>Holds the path to the serial port's pipe on the host when the port is working in <b>Host Pipe</b> mode, or the host serial device name when the port is working in <b>Host Device</b> mode.</source>
- <translation type="unfinished"></translation>
+ <translation>Serie atakaren hodi helburua zehazten du hostalarian ataka <b>Hostalari Hodia</b> moduan ari denean lanean, edo hostalari serie gailua izena ataka <b>Hostalari Gailua</b> moduan ari denean lanean.</translation>
</message>
<message>
<location line="-13"/>
<source>Port/File &Path:</source>
<translation>Ataka/Agiria &Helburua:</translation>
</message>
- <message>
- <source>Displays the base I/O port address of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
- <translation type="obsolete">Serieko ataka honen ohinarri S/I ataka helbidea erakusten du. Baliozko balioak dira <tt>0</tt> eta <tt>0xFFFF</tt> arteko zenbaki osoak.</translation>
- </message>
</context>
<context>
<name>UIMachineSettingsSerialPage</name>
<message>
- <source>Duplicate port number selected </source>
- <translation type="obsolete">Bikoiztu hautaturiko ataka zenbakia </translation>
- </message>
- <message>
- <source>Port path not specified </source>
- <translation type="obsolete">Ataka helburua ez da adierazi </translation>
- </message>
- <message>
- <source>Duplicate port path entered </source>
- <translation type="obsolete">Bikoiztu sartutako ataka helburua </translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsSerial.cpp" line="+251"/>
<source>No IRQ is currently specified.</source>
<translation>Ez dago IRQ-rik adierazita.</translation>
@@ -4731,12 +3978,12 @@
<message>
<location line="+70"/>
<source>Selects the slot on the storage controller used by this attachment. The available slots depend on the type of the controller and other attachments on it.</source>
- <translation type="unfinished"></translation>
+ <translation>Eranspen honek erabiltzen duen biltegi kontrolatzaile eslota hautatzen du. Eslot eskuragarria kontrolatzaile motaren edo bertako beste eranspenen araberakoa da.</translation>
</message>
<message>
<location line="+31"/>
<source>When checked, allows the guest to send ATAPI commands directly to the host-drive which makes it possible to use CD/DVD writers connected to the host inside the VM. Note that writing audio CD inside the VM is not yet supported.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, gonbidatuak hostalari-gidagailura ATAPI aginduak zuzenean bidaltzea ahalbidetzen du, honek makina birtualaren barnean elkartutako CD/DVD idazgailuak erabili ahal izatea egiten du. Ohartu oraindik ez dagoela sostengatua audio CD-ak idaztea MB-ren barnean.</translation>
</message>
<message>
<location line="+3"/>
@@ -4771,7 +4018,7 @@
<message>
<location line="+20"/>
<source>Attached to:</source>
- <translation type="unfinished">Hona Erantsita:</translation>
+ <translation>Hona Erantsita:</translation>
</message>
<message>
<location line="-140"/>
@@ -4779,19 +4026,11 @@
<translation>Mota (Heuskarria):</translation>
</message>
<message>
- <source>Attached To:</source>
- <translation type="obsolete">Hona Erantsita:</translation>
- </message>
- <message>
<location line="-153"/>
<source>Allows to use host I/O caching capabilities.</source>
<translation>Hostalari S/I katxe gaitasunak erabiltzea ahalbidetzen du.</translation>
</message>
<message>
- <source>Use host I/O cache</source>
- <translation type="obsolete">Erabili hostalari S/I katxea</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsStorage.cpp" line="-290"/>
<source>Add SAS Controller</source>
<translation>Gehitu SAS Kontrolatzailea</translation>
@@ -4814,12 +4053,12 @@
<message>
<location line="+1389"/>
<source>No name is currently specified for the controller at position <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ez da izenik adierazi kontrolatzailearentzat <b>%1</b> kokapenean.</translation>
</message>
<message>
<location line="+6"/>
<source>The controller at position <b>%1</b> has the same name as the controller at position <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation><b>%1</b> kokapeneko kontrolatzaileak jadanik <b>%2</b> kokapeneko kontrolatzaileak erabiltzen duen izena erabiltzen du.</translation>
</message>
<message>
<location line="+18"/>
@@ -4829,12 +4068,12 @@
<message>
<location line="+6"/>
<source><i>%1</i> is using a disk that is already attached to <i>%2</i>.</source>
- <translation type="unfinished"></translation>
+ <translation><i>%1</i> jadanik <i>%2</i>-ra erantsita dagoen diska bat erabiltzen ari da.</translation>
</message>
<message>
<location line="+27"/>
<source>The machine currently has more storage controllers assigned than a %1 chipset supports. Please change the chipset type on the System settings page or reduce the number of the following storage controllers on the Storage settings page: %2</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualak une honetan %1 txipsetak sostengatzen dituen baino biltegiratze kontrolatzaile gehiago ditu esleituta. Mesedez aldatu txipset mota Sistema ezarpenak orrialdean edo gutxitu hurrengo biltegiratze kontrolatzaile zenbatekoa Biltegia ezarpenak orrialdean: %2</translation>
</message>
<message>
<location line="+322"/>
@@ -4869,7 +4108,7 @@
<message>
<location line="+2"/>
<source>Choose a virtual floppy disk or a physical drive to use with the virtual drive. The virtual machine will see a disk inserted into the drive with the data in the file or on the disk in the physical drive as its contents.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatu gidagailu birtualarekin erabiltzeko diskete bat edo gidagailu fisiko bat. Makina birtualak gidagailuan txertaturiko diska bat ikusiko du agiriko datuekin edo gidagailu fisikoko diskan bere edukiak bezala.</translation>
</message>
<message>
<location line="+3"/>
@@ -4922,37 +4161,21 @@
<translation>Hautatutakoan gonbidatu sistemak diska birtuala egoera solidoko gailu bat bezala ikusiko du.</translation>
</message>
<message>
- <source>&Solid-state drive</source>
- <translation type="obsolete">&Egoera-solido gidagailua</translation>
- </message>
- <message>
<location line="+117"/>
<source>Details:</source>
- <translation>Xehetasunak:</translation>
- </message>
- <message>
- <source>no name specified for controller at position <b>%1</b>.</source>
- <translation type="obsolete">ez da izenik adierazi kontrolatzailearentzat <b>%1</b> kokapenean.</translation>
- </message>
- <message>
- <source>controller at position <b>%1</b> uses the name that is already used by controller at position <b>%2</b>.</source>
- <translation type="obsolete"><b>%1</b> kokapeneko kontrolatzaileak jadanik <b>%2</b> kokapeneko kontrolatzaileak erabiltzen duen izena erabiltzen du.</translation>
- </message>
- <message>
- <source>no hard disk is selected for <i>%1</i>.</source>
- <translation type="obsolete">ez da diska gogorrik hautatu <i>%1</i>-rako.</translation>
+ <translation>Xehetasunak:</translation>
</message>
<message>
<location filename="../src/settings/machine/UIMachineSettingsStorage.cpp" line="-505"/>
<source>at most one supported</source>
<comment>controller</comment>
- <translation type="unfinished"></translation>
+ <translation>gehienez sostengatuetako bat</translation>
</message>
<message>
<location line="+1"/>
<source>up to %1 supported</source>
<comment>controllers</comment>
- <translation type="unfinished"></translation>
+ <translation>%1-ra arte sostengatuta</translation>
</message>
<message>
<location filename="../src/settings/machine/UIMachineSettingsStorage.ui" line="-279"/>
@@ -4962,7 +4185,7 @@
<message>
<location line="+13"/>
<source>Selects the port count of the SATA storage controller currently selected in the Storage Tree. This must be at least one more than the highest port number you need to use.</source>
- <translation type="unfinished"></translation>
+ <translation>Biltegi Zuhaitzean hautatutako SATA biltegiratze kontrolatzailearen ataka kopurua hautatzen du. Hau gutxienez izan behar da erabiltzea behar duzun ataka zenbateko gehiena baino bat gehiago.</translation>
</message>
<message>
<location filename="../src/VBoxVMInformationDlg.cpp" line="+551"/>
@@ -4976,73 +4199,49 @@
<context>
<name>UIMachineSettingsSystem</name>
<message>
- <source>you have assigned more than <b>%1%</b> of your computer's memory (<b>%2</b>) to the virtual machine. Not enough memory is left for your host operating system. Please select a smaller amount.</source>
- <translation type="obsolete">Zure ordenagailuaren (<b>%2</b>) <b>%1%</b> baino oroimen gehigo duzu esleituta makina birtualera. Ez da nahikoa oroimen gelditzen zure hostalari sistema eragilerako. Mesedez hautatu kopuru txikiago bat.</translation>
- </message>
- <message>
- <source>you have assigned more than <b>%1%</b> of your computer's memory (<b>%2</b>) to the virtual machine. There might not be enough memory left for your host operating system. Continue at your own risk.</source>
- <translation type="obsolete">Zure ordenagailuaren (<b>%2</b>) <b>%1%</b> baino oroimen gehigo duzu esleituta makina birtualera. Badaiteke nahikoa oroimen ez gelditzea zure hostalari sistema eragilerako. Jarraitu zeure arriskupean.</translation>
- </message>
- <message>
- <source>for performance reasons, the number of virtual CPUs attached to the virtual machine may not be more than twice the number of physical CPUs on the host (<b>%1</b>). Please reduce the number of virtual CPUs.</source>
- <translation type="obsolete">egintza zergaitiengaitik, makina birtualera erantsitako CPU birtual zenbatekoa ezin da hostalariko CPU fisikoak (<b>%1</b> baino bi aldiz gehiago izan. Mesedez murriztu CPU birtual zenbatekoa.</translation>
- </message>
- <message>
- <source>you have assigned more virtual CPUs to the virtual machine than the number of physical CPUs on your host system (<b>%1</b>). This is likely to degrade the performance of your virtual machine. Please consider reducing the number of virtual CPUs.</source>
- <translation type="obsolete">zure hostalari sistemak dituen CPU fisiko zenbatekoa (<b>%1</b>) baino CPU birtual gehiago esleitu dizkiozu makina birtualari. Honek zure makina birtualaren egintza itsusituko du. Mesedez kontuan hartu CPU birtual zenbatekoa gutxitzea.</translation>
- </message>
- <message>
- <source>you have assigned more than one virtual CPU to this VM. This will not work unless the IO-APIC feature is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
- <translation type="obsolete">CPU birtual bat baino gehiago esleitu dizkiozu MB honi. Honek ez du lan egingo IO-APIC ezaugarria ere gaituta ez badago. Hau berezgaitasunez egingo da MB Ezarpenak onartzen dituzunean Ongi botoia sakatuz.</translation>
- </message>
- <message>
- <source>you have assigned more than one virtual CPU to this VM. This will not work unless hardware virtualization (VT-x/AMD-V) is also enabled. This will be done automatically when you accept the VM Settings by pressing the OK button.</source>
- <translation type="obsolete">CPU birtual bat baino gehiago esleitu dizkiozu MB honi. Honek ez du lan egingo hardware birtualizazioa (VT-x/AMD-V) ere gaituta ez badago. Hau berezgaitasunez egingo da MB Ezarpenak onartzen dituzunean Ongi botoia sakatuz.</translation>
- </message>
- <message>
<location filename="../src/settings/machine/UIMachineSettingsSystem.cpp" line="+302"/>
<source>More than <b>%1%</b> of the host computer's memory (<b>%2</b>) is assigned to the virtual machine. Not enough memory is left for the host operating system. Please select a smaller amount.</source>
- <translation type="unfinished"></translation>
+ <translation>Zure ordenagailuaren (<b>%2</b>) <b>%1%</b> baino oroimen gehigo duzu esleituta makina birtualera. Ez da nahikoa oroimen gelditzen zure hostalari sistema eragilerako. Mesedez hautatu kopuru txikiago bat.</translation>
</message>
<message>
<location line="+9"/>
<source>More than <b>%1%</b> of the host computer's memory (<b>%2</b>) is assigned to the virtual machine. There might not be enough memory left for the host operating system. Please consider selecting a smaller amount.</source>
- <translation type="unfinished"></translation>
+ <translation>Zure ordenagailuaren (<b>%2</b>) <b>%1%</b> baino oroimen gehigo duzu esleituta makina birtualera. Ez da nahikoa oroimen gelditzen zure hostalari sistema eragilerako. Mesedez hautatu kopuru txikiago bat.</translation>
</message>
<message>
<location line="+10"/>
<source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support a chip set of type ICH9. It will be done automatically if you confirm your changes.</source>
- <translation type="unfinished"></translation>
+ <translation>I/O APIC ezaugarria une honetan ez dago gaituta Sistema orrialdeko ohinplaka atalean. Hau beharrezkoa da MB honentzat gaituta duzun ICH9 motako txipset bat sostengatzerako orduan. Berezgaitasunez egingo da zure aldaketak baieztatzen badituzu.</translation>
</message>
<message>
<location line="+9"/>
<source>USB controller emulation is not currently enabled on the USB page. This is needed to support an emulated USB input device. It will be done automatically if you confirm your changes.</source>
- <translation type="unfinished"></translation>
+ <translation>USB kontrolatzaile emulazioa ez dago gaituta USB orrialdean. Hau beharrezkoa da emulatutako USB sarrera gailu bat sostengatzeko. Hau berezgaitasunez egingo aldaketak baieztatzen badituzu.</translation>
</message>
<message>
<location line="+21"/>
<source>For performance reasons, the number of virtual CPUs attached to the virtual machine may not be more than twice the number of physical CPUs on the host (<b>%1</b>). Please reduce the number of virtual CPUs.</source>
- <translation type="unfinished"></translation>
+ <translation>Egintza zergaitiengaitik, makina birtualera erantsitako CPU birtual zenbatekoa ezin da hostalariko CPU fisikoak (<b>%1</b> baino bi aldiz gehiago izan. Mesedez murriztu CPU birtual zenbatekoa.</translation>
</message>
<message>
<location line="+8"/>
<source>More virtual CPUs are assigned to the virtual machine than the number of physical CPUs on the host system (<b>%1</b>). This is likely to degrade the performance of your virtual machine. Please consider reducing the number of virtual CPUs.</source>
- <translation type="unfinished"></translation>
+ <translation>Zure hostalari sistemak dituen CPU fisiko zenbatekoa (<b>%1</b>) baino CPU birtual gehiago esleitu dizkiozu makina birtualari. Honek zure makina birtualaren egintza itsusituko du. Mesedez kontuan hartu CPU birtual zenbatekoa gutxitzea.</translation>
</message>
<message>
<location line="+9"/>
<source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support more than one virtual processor. It will be done automatically if you confirm your changes.</source>
- <translation type="unfinished"></translation>
+ <translation>I/O APIC ezaugarria une honetan ez dago gaituta Sistema orrialdeko Ohinplaka atalean. Hau beharrezkoa da prozesagailu birtual bat baino gehiago sostengatzerako orduan. Berezgaitasunez egingo da zure aldaketak baieztatzen badituzu.</translation>
</message>
<message>
<location line="+9"/>
<source>Hardware virtualization is not currently enabled in the Acceleration section of the System page. This is needed in order to support more than one virtual processor. It will be done automatically if you confirm your changes.</source>
- <translation type="unfinished"></translation>
+ <translation>Hardware birtualizazioa une honetan ez dago gaituta Bizkorpena ataleko Sistema orrialdean. Hau beharrezkoa da prozesagailu birtual bat baino gehiago sostengatzerako orduan. Hau berezgaitasunez egingo da zure aldaketak baieztatzen badituzu.</translation>
</message>
<message>
<location line="+9"/>
<source>The processor execution cap is set to a low value. This may make the machine feel slow to respond.</source>
- <translation type="unfinished"></translation>
+ <translation>Prozesagailuaren exekuzio muga bailo apal batean ezarri duzu. Honek makinak astiro erantzutea eragingo du.</translation>
</message>
<message>
<location line="+49"/>
@@ -5064,7 +4263,7 @@
<message>
<location line="+6"/>
<source>Base &Memory:</source>
- <translation>&Ohinarri Oroimena:</translation>
+ <translation>O&hinarri Oroimena:</translation>
</message>
<message>
<location line="+25"/>
@@ -5114,10 +4313,6 @@
<translation>Ezaugarri Hedatuak:</translation>
</message>
<message>
- <source>Enable &IO APIC</source>
- <translation type="obsolete">Gaitu &IO APIC</translation>
- </message>
- <message>
<location line="-140"/>
<source>&Processor</source>
<translation>&Prozesagailuak</translation>
@@ -5130,7 +4325,7 @@
<message>
<location line="+144"/>
<source>When checked, the Physical Address Extension (PAE) feature of the host CPU will be exposed to the virtual machine.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, hostalari CPU-aren Helbide Fisiko Hedapena (PAE) ezaugarria agerian jarriko da makina birtualarentzat.</translation>
</message>
<message>
<location line="+3"/>
@@ -5160,7 +4355,7 @@
<message>
<location line="+13"/>
<source>When checked, the virtual machine will try to make use of the nested paging extension of Intel VT-x and AMD-V.</source>
- <translation type="unfinished"></translation>
+ <translation>Huatutakoan, makina birtuala Intel VT-x eta AMD-V nested orrialdeztapen hedapena erabiltzen saiatuko da.</translation>
</message>
<message>
<location line="+3"/>
@@ -5176,7 +4371,7 @@
<message>
<location filename="../src/settings/machine/UIMachineSettingsSystem.ui" line="-246"/>
<source>When checked, the guest will support the Extended Firmware Interface (EFI), which is required to boot certain guest OSes. Non-EFI aware OSes will not be able to boot if this option is activated.</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, gonbidatuak Firmware Hedatu Interfazea (EFI) sostengatuko du, hau beharrezkoa da zenbait gonbidatu SE abiarazteko. Ez-EFI SE-ak ez dira abiatzeko gai izango aukera hau gaituta badago.</translation>
</message>
<message>
<location line="+3"/>
@@ -5186,11 +4381,7 @@
<message>
<location line="+7"/>
<source>If checked, the RTC device will report the time in UTC, otherwise in local (host) time. Unix usually expects the hardware clock to be set to UTC.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Hardware clock in &UTC time</source>
- <translation type="obsolete">Hardware ordularia &UTC orduan</translation>
+ <translation>Hautatzen bada, RTC gailuak ordua UTC moduan jakinaraziko du, bestela tokiko (hostalaria) orduan. Unix-ek arrunt ordularia UTC-an ezarrita egotea itxaroten du.</translation>
</message>
<message>
<location line="+55"/>
@@ -5201,27 +4392,27 @@
<message>
<location line="-210"/>
<source>&Chipset:</source>
- <translation>&Chipseta:</translation>
+ <translation>&Txipseta:</translation>
</message>
<message>
<location line="+21"/>
<source>Selects the chipset to be emulated in this virtual machine. Note that the ICH9 chipset emulation is experimental and not recommended except for guest systems (such as Mac OS X) which require it.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtual honetan emulatuko den txipseta hautatzen du. Ohartu ICH9 txipset emulazioa esperimentala dela eta ez dago gomendatua hori behar duten gonbidatu sistementzat ezik (MAC OS X bezalakoak).</translation>
</message>
<message>
<location line="+22"/>
<source>&Pointing Device:</source>
- <translation type="unfinished"></translation>
+ <translation>&Zuzentze Gailua:</translation>
</message>
<message>
<location line="+21"/>
<source>Determines whether the emulated pointing device is a standard PS/2 mouse, a USB tablet or a USB multi-touch tablet.</source>
- <translation type="unfinished"></translation>
+ <translation>Emulatutako zuzentze gailua PS/2 sagu estandar bat, USB tablet bat edo ikutu-anitzeko USB tablet bat den zehazten du.</translation>
</message>
<message>
<location line="+32"/>
<source>When checked, the virtual machine will support the Input Output APIC (I/O APIC), which may slightly decrease performance. <b>Note:</b> don't disable this feature after having installed a Windows guest operating system!</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatutakoan, makina birtualak Sarrera Irteera APIC (I/O APIC) sostengatuko du, honek apur bat gutxitu dezake egintza. <b>Oharra:</b> ez ezgaitu ezaugarri hau Windows gonbidatu sistema eragile bat ezarri ondoren!</translation>
</message>
<message>
<location line="+3"/>
@@ -5242,11 +4433,7 @@
<location line="+18"/>
<location line="+38"/>
<source>Limits the amount of time that each virtual CPU is allowed to run for. Each virtual CPU will be allowed to use up to this percentage of the processing time available on one physical CPU. The execution cap can be disabled by setting it to 100%. Setting the cap too low can make the machine feel slow to respond.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>you have set the processor execution cap to a low value. This can make the machine feel slow to respond.</source>
- <translation type="obsolete">exekuzio muga bailo apal batean ezarri duzu. Honek makinak astiro erantzutea eragingo du.</translation>
+ <translation>CPU birtual bakoitzak ekiteko duen denbora kopurua mugatzen du. CPU birtual bakoitza CPU fisiko batean eskuragarri dagoen prozesapen denbora ehuneko honetara arte erabiltzeko ahalbidetuko da. Exekuzio muga ezgaitu egin daiteke hura 100%-ean ezarriz. Muga oso txikia ezarriz gero makina erantzuteko motela dela iruditzea egin dezake.</translation>
</message>
<message>
<location filename="../src/settings/machine/UIMachineSettingsSystem.cpp" line="+3"/>
@@ -5266,7 +4453,7 @@
<message>
<location filename="../src/settings/machine/UIMachineSettingsUSB.cpp" line="+438"/>
<source>USB 2.0 is currently enabled for this virtual machine. However, this requires the <b>%1</b> to be installed. Please install the Extension Pack from the VirtualBox download site or disable USB 2.0 to be able to start the machine.</source>
- <translation type="unfinished"></translation>
+ <translation>USB 2.0 une honetan gaituta dago makina birtual honetan. Horrela ere, <i>%1</i> ezarrita behar du. Mesedez ezarri Hedapen Paketea VirtualBox jeisketa gunetik edo ezgaitu USB 2.0 makina abiatu ahal izateko.</translation>
</message>
<message>
<location line="+27"/>
@@ -5301,7 +4488,7 @@
<message>
<location line="+15"/>
<source>Adds a new USB filter with all fields initially set to empty strings. Note that such a filter will match any attached USB device.</source>
- <translation type="unfinished"></translation>
+ <translation>USB iragazki berri bat gehitzen du hasiera batean eremu guztiak kate hutsetan ezarrita daudela. Ohartu iragazki honek erantsitako edozein USB gailu aurkituko duela.</translation>
</message>
<message>
<location line="+4"/>
@@ -5444,13 +4631,9 @@
<translation>&Izena:</translation>
</message>
<message>
- <source>Displays the filter name.</source>
- <translation type="obsolete">Iragazki izena erakusten du.</translation>
- </message>
- <message>
<location line="+13"/>
<source>Holds the filter name.</source>
- <translation type="unfinished"></translation>
+ <translation>Iragazki izena zehazten du.</translation>
</message>
<message>
<location line="+7"/>
@@ -5480,7 +4663,7 @@
<message>
<location line="+13"/>
<source>Defines the revision number filter. The <i>exact match</i> string format is <tt>IIFF</tt> where <tt>I</tt> is a decimal digit of the integer part and <tt>F</tt> is a decimal digit of the fractional part. An empty string will match any value.</source>
- <translation type="unfinished"></translation>
+ <translation>Berrikuspen iragazkia zehazten du. <i>berdin zehatz</i> kate heuskarria da <tt>IIFF</tt> non <tt>I</tt> zenbaki oso baten hamarrena den eta <tt>F</tt> zatizki harrarren bat den. Kate huts batek edozein balio berdinduko du.</translation>
</message>
<message>
<location line="+7"/>
@@ -5530,11 +4713,7 @@
<message>
<location line="+19"/>
<source>Defines whether this filter applies to USB devices attached locally to the host computer (<i>No</i>), to a VRDP client's computer (<i>Yes</i>), or both (<i>Any</i>).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>&Action:</source>
- <translation type="obsolete">&Ekintza:</translation>
+ <translation>Iragazki hau hostalari ordenagailuari tokian erantsitako USB gailuei ezartzen zaien zehazten du (<i>Ez</i>), VRDP bezereroaren ordenagailuari (<i>Bai</i>), edo biei (<i>Edozein</i>).</translation>
</message>
<message>
<location line="-185"/>
@@ -5555,7 +4734,7 @@
<message>
<location filename="../src/runtime/normal/UIMachineWindowNormal.cpp" line="+558"/>
<source>Shows the currently assigned Host key.<br>This key, when pressed alone, toggles the keyboard and mouse capture state. It can also be used in combination with other keys to quickly perform actions from the main menu.</source>
- <translation type="unfinished"></translation>
+ <translation>Orain esleitutako Hostalari tekla erakusten du.<br>Tekla hau, bera bakarrik sakatzen denean, teklatuaren eta saguaren hartze egoerak aldatzen ditu. Beste tekla batzuekin konbinatuta edo erabili daiteke menu nagusitik ekintza azkarrak burutzeko.</translation>
</message>
</context>
<context>
@@ -5576,10 +4755,6 @@
<translation>Diskete &diskak</translation>
</message>
<message>
- <source>&Select</source>
- <translation type="obsolete">&Hautatu</translation>
- </message>
- <message>
<location line="+17"/>
<source>C&lose</source>
<translation>It&xi</translation>
@@ -5590,12 +4765,12 @@
<message>
<location filename="../src/UIMediumTypeChangeDialog.cpp" line="+113"/>
<source>Modify medium attributes</source>
- <translation type="unfinished"></translation>
+ <translation>Aldatu medioaren ezaugarriak</translation>
</message>
<message>
<location line="+3"/>
<source><p>You are about to change the settings of the disk image file <b>%1</b>.</p><p>Please choose one of the following modes and press <b>%2</b> to proceed or <b>%3</b> otherwise.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>%1</b> diska irudi agiriaren ezarpenak aldatzear zaude.</p><p>Mesedez hautatu hurrengo moduetako bat eta sakatu <b>%2</b> jarraitzeko edo <b>%3</b> bestela.</p></translation>
</message>
<message>
<location line="+8"/>
@@ -5643,170 +4818,170 @@
<message>
<location line="-1852"/>
<source><p>Do you want to remove the NAT network <nobr><b>%1</b>?</nobr></p><p>If this network is in use by one or more virtual machine network adapters these adapters will no longer be usable until you correct their settings by either choosing a different network name or a different adapter attachment type.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Kentzea nahi duzu <nobr><b>%1</b> NAT sarea?</nobr></p><p>Sare hau makina birtual sare egokitzaile batek edo gehiagok erabiltzen badute egokitzaile hauek ez dira erabilgarriak izango beren ezarpenak zuzentzen dituzun arte sare izen edo egokitzaile eranspen mota ezberdin bat hautatuz.</p></translation>
</message>
<message>
<location line="+30"/>
<source>Failed to create NAT network.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea NAT sarea sortzerakoan.</translation>
</message>
<message>
<location line="+7"/>
<source>Failed to remove NAT network <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> NAT sarea kentzerakoan.</translation>
</message>
<message>
<location line="+8"/>
<source>Failed to create DHCP server.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea DHCP zerbitzaria sortzerakoan.</translation>
</message>
<message>
<location line="+7"/>
<source>Failed to remove DHCP server for network interface <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> DHCP zerbitzaria sare interfazetik kentzerakoan.</translation>
</message>
<message>
<location line="+8"/>
<location line="+7"/>
<source>Failed to create the host network interface.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea hostalariaren sare interfazea sortzerakoan.</translation>
</message>
<message>
<location line="+73"/>
<source>Create &new disk</source>
- <translation type="unfinished">&Sortu diska berria</translation>
+ <translation>&Sortu diska berria</translation>
</message>
<message>
<location line="+0"/>
<source>&Choose existing disk</source>
- <translation type="unfinished">&Hautatu badagoen diska</translation>
+ <translation>&Hautatu badagoen diska</translation>
</message>
<message>
<location line="+11"/>
<location line="+11"/>
<source>Leave &empty</source>
- <translation type="unfinished">Utzi &hutsik</translation>
+ <translation>Utzi &hutsik</translation>
</message>
<message>
<location line="-11"/>
<location line="+11"/>
<source>&Choose disk</source>
- <translation type="unfinished">&Hautatu diska</translation>
+ <translation>&Hautatu diska</translation>
</message>
<message>
<location line="+6"/>
<source><p>Are you sure you want to delete the CD/DVD device?</p><p>You will not be able to insert any CDs or ISO images or install the Guest Additions without it!</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude CD/DVD gailua ezabatzea nahi duzula?</p><p>Ezingo duzu CD/DVD edo ISO irudirik txertatu edo Gonbidatu Gehigarririk ezarri bera gabe!</p></translation>
</message>
<message>
<location line="+104"/>
<source><p>Error changing disk image mode from <b>%1</b> to <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Akatsa diska irudi modua <b>%1</b>-tik <b>%2</b>-ra aldatzerakoan.</p></translation>
</message>
<message>
<location line="+13"/>
<source><p>Are you sure you want to release the virtual hard disk <nobr><b>%1</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diska gogor birtuala askatzea nahi duzula?</p><p>Honek hurrengo makina birtuale(ta)tik deserantsiko du: <b>%2</b>.</p></translation>
</message>
<message>
<location line="+6"/>
<source><p>Are you sure you want to release the virtual optical disk <nobr><b>%1</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diska optiko birtuala askatzea nahi duzula?</p><p>Honek hurrengo makina birtuale(ta)tik deserantsiko du: <b>%2</b>.</p></translation>
</message>
<message>
<location line="+6"/>
<source><p>Are you sure you want to release the virtual floppy disk <nobr><b>%1</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diskete birtuala askatzea nahi duzula?</p><p>Honek hurrengo makina birtuale(ta)tik deserantsiko du: <b>%2</b>.</p></translation>
</message>
<message>
<location line="+22"/>
<source><p>Are you sure you want to remove the virtual hard disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diska gogor birtuala kentzea nahi duzula diska irudi agiri ezagunen zerrendatik?</p></translation>
</message>
<message>
<location line="+12"/>
<source><p>As this hard disk is inaccessible its image file can not be deleted.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Diska gogor hau eskuraezina denez bere irudi agiria ezin da ezabatu.</p></translation>
</message>
<message>
<location line="+7"/>
<source><p>Are you sure you want to remove the virtual optical disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diska optiko birtuala diska irudi agiri ezagunen zerrendatik kentzea nahi duzula?</p></translation>
</message>
<message>
<location line="+8"/>
<source><p>Are you sure you want to remove the virtual floppy disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> diskete birtuala kentzea nahi duzula diska irudi agiri ezagunen zerrendatik?</p></translation>
</message>
<message>
<location line="+91"/>
<source><p>Unable to insert the virtual optical disk <nobr><b>%1</b></nobr> into the machine <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezinezkoa <nobr><b>%1</b></nobr> diska optiko birtuala <b>%2</b> makinan txertatzea.</p></translation>
</message>
<message>
<location line="+2"/>
<location line="+16"/>
<source><p>Would you like to try to force insertion of this disk?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Nahi duzu diska honen txertatzea behartzea?</p></translation>
</message>
<message>
<location line="-12"/>
<source><p>Unable to eject the virtual optical disk <nobr><b>%1</b></nobr> from the machine <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezinezkoa <nobr><b>%1</b></nobr> diska optiko birtuala <b>%2</b> makinatik ateratzea.</p></translation>
</message>
<message>
<location line="+2"/>
<location line="+16"/>
<source><p>Would you like to try to force ejection of this disk?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Nahi duzu diska honen ateratzea behartzea?</p></translation>
</message>
<message>
<location line="-8"/>
<source><p>Unable to insert the virtual floppy disk <nobr><b>%1</b></nobr> into the machine <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezinezkoa <nobr><b>%1</b></nobr> diskete birtuala <b>%2</b> makinan txertatzea.</p></translation>
</message>
<message>
<location line="+6"/>
<source><p>Unable to eject the virtual floppy disk <nobr><b>%1</b></nobr> from the machine <b>%2</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezinezkoa <nobr><b>%1</b></nobr> diskete birtuala <b>%2</b> makinatik ateratzea.</p></translation>
</message>
<message>
<location line="+30"/>
<source>Failed to open the hard disk file <nobr><b>%1</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%1</b></nobr> diska gogor agiria irekitzerakoan.</translation>
</message>
<message>
<location line="+5"/>
<source>Failed to open the optical disk file <nobr><b>%1</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%1</b></nobr> diska optiko agiria irekitzerakoan.</translation>
</message>
<message>
<location line="+5"/>
<source>Failed to open the floppy disk file <nobr><b>%1</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%1</b></nobr> diskete agiria irekitzerakoan.</translation>
</message>
<message>
<location line="+19"/>
<source>Failed to close the hard disk file <nobr><b>%2</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%2</b></nobr> diska gogor agiria isterakoan.</translation>
</message>
<message>
<location line="+5"/>
<source>Failed to close the optical disk file <nobr><b>%2</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%2</b></nobr> diska optiko agiria isterakoan.</translation>
</message>
<message>
<location line="+5"/>
<source>Failed to close the floppy disk file <nobr><b>%2</b></nobr>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <nobr><b>%2</b></nobr> diskete agiria isterakoan.</translation>
</message>
<message numerus="yes">
<location line="+156"/>
<source><p>The %n following virtual machine(s) are currently in a saved state: <b>%1</b></p><p>If you continue the runtime state of the exported machine(s) will be discarded. The other machine(s) will not be changed.</p></source>
<comment>This text is never used with n == 0. Feel free to drop the %n where possible, we only included it because of problems with Qt Linguist (but the user can see how many machines are in the list and doesn't need to be told).</comment>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform><p>Hurrengo %n makina birtuala gordeta egoeran dago: <b>%1</b></p><p>Jardunean jarraitzen baduzu esportatutako makinaren egoera baztertu egingo da. Beste makina(k) ez d(ir)a aldatuko.</p></numerusform>
+ <numerusform><p>Hurrengo %n makina birtualak gordeta egoeran daude: <b>%1</b></p><p>Jardunean jarraitzen baduzu esportatutako makinaren egoera baztertu egingo da. Beste makina(k) ez d(ir)a aldatuko.</p></numerusform>
</translation>
</message>
<message>
@@ -5814,57 +4989,57 @@
<location line="+13"/>
<location line="+13"/>
<source>Switch</source>
- <translation type="unfinished">Aldatu</translation>
+ <translation>Aldatu</translation>
</message>
<message>
<location line="-7"/>
<source><p>The virtual machine window will be now switched to <b>Scale</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in scaled mode. You can access it by pressing <b>Host+Home</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Makina birtualaren leihoa orain <b>Eskalatua</b> modura aldatuko da. Leihotu modura itzuli zaitezke <b>%1</b> sakatuz.</p><p>Ohartu <i>Host</i> tekla <b>%2</b> bezala zehaztua dagoela.</p><p>Ohartu ere menu barra nagusia ezkutatu egiten dela eskalatua moduan. Bertara <b>Host+Home</b> sakatuz sartu zaitezke.</p></translation>
</message>
<message>
<location line="+87"/>
<source>Failed to attach the webcam <b>%1</b> to the virtual machine <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> webkamera <b>%2</b>makina birtualera eransterakoan.</translation>
</message>
<message>
<location line="+8"/>
<source>Failed to detach the webcam <b>%1</b> from the virtual machine <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> webkamera <b>%2</b>makina birtualetik deseransterakoan.</translation>
</message>
<message>
<location line="+9"/>
<source>Failed to enable the remote desktop server for the virtual machine <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> makina birtualarentzako hurruneko mahaigain zerbitzaria gaitzerakoan.</translation>
</message>
<message>
<location line="+1"/>
<source>Failed to disable the remote desktop server for the virtual machine <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> makina birtualarentzako hurruneko mahaigain zerbitzaria ezgaitzerakoan.</translation>
</message>
<message>
<location line="+10"/>
<source>Failed to enable video capturing for the virtual machine <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> makina birtualaren bideo harpena gaitzerakoan.</translation>
</message>
<message>
<location line="+1"/>
<source>Failed to disable video capturing for the virtual machine <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> makina birtualaren bideo harpena ezgaitzerakoan.</translation>
</message>
<message>
<location line="+7"/>
<source><p>The VirtualBox Guest Additions do not appear to be available on this virtual machine, and shared folders cannot be used without them. To use shared folders inside the virtual machine, please install the Guest Additions if they are not installed, or re-install them if they are not working correctly, by selecting <b>Insert Guest Additions CD image</b> from the <b>Devices</b> menu. If they are installed but the machine is not yet fully starte [...]
- <translation type="unfinished"></translation>
+ <translation><p>VirtualBox Gonbidatu Gehigarriak ez dira eskuragarri bezala agertzen makina birtual honetan, eta elkarbanatutako agiritegiak ezingo dira erabili horiek gabe. Elkarbanatutako agiritegiak makina birtualaren barnean erabiltzeko, mesedez ezarri Gonbidatu Gehigarriak ezarrita ez badaude, edo ber-ezarri zuzen lan egiten ez badute, <b>Txertatu Gonbidatu Gehigarriak CD irudia</b> hautatuz <b>Gailuak</b> menuan. Ezarrita badaude baina makina o [...]
</message>
<message>
<location line="+11"/>
<source><p>Could not insert the <b>VirtualBox Guest Additions</b> disk image file into the virtual machine <b>%1</b>, as the machine has no CD/DVD drives. Please add a drive using the storage page of the virtual machine settings window.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da <b>VirtualBox Gonbidatu Gehigarriak</b> diska irudi agiria txertatu <b>%1</b> makina birtualean, makinak ez duelako CD/DVD gidagailurik. Mesedez gehitu gidagailu bat biltegia orrialdea erabiliz makina birtualaren ezarpenak leihoan.</p></translation>
</message>
<message>
<location line="+40"/>
<source><p>Could not find the <b>VirtualBox Guest Additions</b> disk image file.</p><p>Do you wish to download this disk image file from the Internet?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da<b>VirtualBox Gonbidatu Gehigarriak</b> diska irudi agiria aurkitu.</p><p>Nahi duzu diska irudi agiria Internetetik jeistea?</p></translation>
</message>
<message>
<location line="+3"/>
@@ -5874,22 +5049,22 @@
<location line="+29"/>
<location line="+10"/>
<source>Download</source>
- <translation type="unfinished">Jeitsi</translation>
+ <translation>Jeitsi</translation>
</message>
<message>
<location line="-93"/>
<source><p>Are you sure you want to download the <b>VirtualBox Guest Additions</b> disk image file from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude VirtualBox Gonbidatu Gehigarriak diska irudia <nobr><a href="%1">%1</a></nobr>-tik (neurria %2 byte) jeistea nahi duzula?</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> but can't be saved locally as <nobr><b>%2</b>.</nobr></p><p>Please choose another location for that file.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>VirtualBox Gonbidatu Gehigarriak</b> diska irudi agiria ongi jeitsi da<nobr><a href="%1">%1</a></nobr>-tik baina ezin da tokian bertan gorde honela: <nobr><b>%2</b>.</nobr></p><p>Mesedez hautatu beste kokaleku bat agiriarentzat.</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>.</nobr></p><p>Do you wish to register this disk image file and insert it into the virtual CD/DVD drive?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>VirtualBox Gonbidatu Gehigarriak</b> diska irudi agiria ongi jeitsi da <nobr><a href="%1">%1</a></nobr>-tik eta tokian bertan gorde da <nobr><b>%2</b> bezala.</nobr></p><p>Nahi duzu diska irudi agiria erregistratzea eta CD/DVD gidagailuan txertatzea?</p></translation>
</message>
<message>
<location line="+6"/>
@@ -5900,27 +5075,27 @@
<message>
<location line="+6"/>
<source>Failed to update Guest Additions. The Guest Additions disk image file will be inserted for user installation.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsgitea Gonbidatu Gehigarriak eguneratzerakoan. Gonbidatu Gehigarriak diska irudi agiria txertatuko da erabiltzaileak ezartzeko.</translation>
</message>
<message>
<location line="+8"/>
<source><p>Could not find the <b>VirtualBox User Manual</b> <nobr><b>%1</b>.</nobr></p><p>Do you wish to download this file from the Internet?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da <nobr><b>%1</b>.</nobr> <b>VirtualBox Erabiltzaile Eskuliburua</b>.</p><p>Nahi duzu diska irudi agiria Internetetik jeistea?</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>Are you sure you want to download the <b>VirtualBox User Manual</b> from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude VirtualBox Erabiltzaile Eskuliburua jeistea nahi duzula hemendik, <nobr><a href="%1">%1</a></nobr>> (neurria %2 byte)?</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> but can't be saved locally as <nobr><b>%2</b>.</nobr></p><p>Please choose another location for that file.</p></source>
- <translation type="unfinished"><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%2</a></nobr>baina ezin da tokian gorde honela <nobr><b>%3</b>.</nobr></p><p>Mesedez hautatu beste kokaleku bat agiriarentzat.</p> {1"?} {1<?} {2<?}</translation>
+ <translation><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik <nobr><a href="%1">%1</a></nobr>-tik baina ezin da tokian bertan gorde honela <nobr><b>%2</b>.</nobr></p><p>Mesedez hautatu beste kokaleku bat agiriarentzat.</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>.</nobr></p></source>
- <translation type="unfinished"><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%2</a></nobr> eta tokian gorde da honela <nobr><b>%3</b>.</nobr></p> {1"?} {1<?} {2<?}</translation>
+ <translation><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%1</a></nobr> eta tokian bertan gorde da honela <nobr><b>%2</b>.</nobr></p></translation>
</message>
<message>
<location line="+655"/>
@@ -5959,14 +5134,6 @@
<translation>Hutsegitea makina birtual berri bat sortzerakoan.</translation>
</message>
<message>
- <source>Failed to create a new virtual machine <b>%1</b>.</source>
- <translation type="obsolete">Hutsegitea makina birtual berri bat sortzerakoan. <b>%1</b>.</translation>
- </message>
- <message>
- <source>Failed to apply the settings to the virtual machine <b>%1</b>.</source>
- <translation type="obsolete">Hutsegitea <b>%1</b> makina birtualari ezarpenak ezartzerakoan.</translation>
- </message>
- <message>
<location line="+342"/>
<location line="+8"/>
<source>Failed to start the virtual machine <b>%1</b>.</source>
@@ -5992,7 +5159,7 @@
<location line="+84"/>
<location line="+8"/>
<source>Failed to create a snapshot of the virtual machine <b>%1</b>.</source>
- <translation>Hutsegitea <b>%1</b> makina birtualaren argazki bat sortzerakoan.</translation>
+ <translation>Hutsegitea <b>%1</b> makina birtualaren berehalako bat sortzerakoan.</translation>
</message>
<message>
<location line="-76"/>
@@ -6052,23 +5219,19 @@
<translation>Hutsegitea <b>%1</b> agiritegi elkarbanatua sortzerakoan (zuzentzen <nobr><b>%2</b></nobr>-ra) <b>%3</b> makina birtualerako.</translation>
</message>
<message>
- <source>Failed to remove the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) from the virtual machine <b>%3</b>.</source>
- <translation type="obsolete">Hutsegitea <b>%1</b> agiritegi elkarbanatua kentzerakoan (zuzentzen <nobr><b>%2</b></nobr>-ra) <b>%3</b> makina birtualerako.</translation>
- </message>
- <message>
<location filename="../src/globals/UIPopupCenter.cpp" line="+195"/>
<source>Close</source>
- <translation type="unfinished">Itxi</translation>
+ <translation>Itxi</translation>
</message>
<message>
<location line="+45"/>
<source>Ok</source>
- <translation type="unfinished">Ongi</translation>
+ <translation>Ongi</translation>
</message>
<message>
<location line="+218"/>
<source><p>The Virtual Machine reports that the guest OS does not support <b>mouse pointer integration</b> in the current video mode. You need to capture the mouse (by clicking over the VM display or pressing the host key) in order to use the mouse inside the guest OS.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Makina Birtualak jakinarazi du gonbidatu SE-k ez duela <b>sagu punta baterapena</b> sostengatzen oraingo bideo moduan. Sagua hartu behar duzu (MB-ren gainean klikatuz edo host tekla sakatuz) sagua erabiltzeko gonbidatu SE-ren barnean.</p></translation>
</message>
<message>
<location line="+10"/>
@@ -6078,11 +5241,7 @@
<message>
<location line="+14"/>
<source><p>The virtual screen is currently set to a <b>%1 bit</b> color mode. For better performance please change this to <b>%2 bit</b>. This can usually be done from the <b>Display</b> section of the guest operating system's Control Panel or System Settings.</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p>Cannot run VirtualBox in <i>VM Selector</i> mode due to local restrictions.</p><p>The application will now terminate.</p></source>
- <translation type="obsolete"><p>Ezin da VirtualBox<i>MB Hautatzailea</i>n moduan ekin tokiko murrizpenengaitik.</p><p>Orain aplikazioa amaitu egingo da.</p></translation>
+ <translation><p>Ikusleiho birtuala une honetan <b>%1 bit</b> margo modu batean ezarrita dago. Egintza hoberako mesedez aldatu hau <b>%2 bit</b>-ra. Hau arrunt gonbidatu sistema eragilearen Aginte Panela edo Sistema Ezarpenak-ko <b>Erakuspena</b> ataletik egin daiteke.</p></translation>
</message>
<message>
<location filename="../src/globals/UIMessageCenter.cpp" line="+519"/>
@@ -6152,21 +5311,13 @@
<location line="+9"/>
<source>Callee: </source>
<comment>error info</comment>
- <translation type="unfinished"></translation>
+ <translation>Deitua: </translation>
</message>
<message>
<location line="+8"/>
<source>Callee RC: </source>
<comment>error info</comment>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p>Could not find a language file for the language <b>%1</b> in the directory <b><nobr>%2</nobr></b>.</p><p>The language will be temporarily reset to the system default language. Please go to the <b>Preferences</b> dialog which you can open from the <b>File</b> menu of the main VirtualBox window, and select one of the existing languages on the <b>Language</b> page.</p></source>
- <translation type="obsolete"><p>Ezin da <b>%1</b> hizkuntzarako hizkuntza agiria aurkitu <b><nobr>%2</nobr></b> zuzenbidean.</p><p>Hizkuntza aldibaterako Ingeleran (barne-eraikita) berrezarriko da. Mesedez joan <b>Hobespenak</b> elkarrizketara VirtualBox leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean dauden hizkuntzetako bat.</p></translation>
- </message>
- <message>
- <source><p>Could not load the language file <b><nobr>%1</nobr></b>. <p>The language will be temporarily reset to English (built-in). Please go to the <b>Preferences</b> dialog which you can open from the <b>File</b> menu of the main VirtualBox window, and select one of the existing languages on the <b>Language</b> page.</p></source>
- <translation type="obsolete"><p>Ezin da <b><nobr>%1</nobr></b> hizkuntza agiria gertatu. <p>Hizkuntza aldibaterako Ingeleran (barne-eraikita) berrezarriko da. Mesedez joan <b>Hobespenak</b> elkarrizketara VirtualBox leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean dauden hizkuntzetako bat.</p></translation>
+ <translation>Deitua RC: </translation>
</message>
<message>
<location line="-1543"/>
@@ -6175,14 +5326,6 @@
<translation><p>Hutsegitea <b>%1</b> elkarbanatutako agiritegia kentzerakoan (hona zuzentzeno <nobr><b>%2</b></nobr>) <b>%3</b> makina birtutaletik.</p><p>Mesedez itxi elkarbanatutako agiritegi hau erabiltzen egon daitezkeen SE gonbidatuko programa guztiak eta saiatu berriro.</p></translation>
</message>
<message>
- <source><p>Are you sure you want to download the VirtualBox Guest Additions CD image from <nobr><a href="%1">%2</a></nobr> (size %3 bytes)?</p></source>
- <translation type="obsolete"><p>Zihur zaude VirtualBox Gonbidatu Gehigarriak CD irudia <nobr><a href="%1">%2</a></nobr>-tik (neurria %3 byte) jeistea nahi duzula?</p></translation>
- </message>
- <message>
- <source>Failed to find license files in <nobr><b>%1</b></nobr>.</source>
- <translation type="obsolete">Hutsegitea baimen agiriak aurkitzerakoan, <nobr><b>%1</b></nobr>.</translation>
- </message>
- <message>
<location line="+1170"/>
<source>Failed to open the license file <nobr><b>%1</b></nobr>. Check file permissions.</source>
<translation>Hutsegitea <nobr><b>%1</b></nobr> baimen agiria irekitzerakoan. Egiaztatu agiri baimenak.</translation>
@@ -6190,11 +5333,7 @@
<message>
<location line="-1549"/>
<source>Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p>Congratulations! You have been successfully registered as a user of VirtualBox.</p><p>Thank you for finding time to fill out the registration form!</p></source>
- <translation type="obsolete"><p>Zorionak! Ongi erregistratu zara VirtualBox erabiltzaile bezala.</p><p>Mila esker erregistrazio galdekizuna betetzeko astia aurkitzeagaitik!</p></translation>
+ <translation>Hutsegitea ACPI Indar Botoi sakatze gertaera <b>%1</b> makina birtualera bildatzerakoan.</translation>
</message>
<message>
<location line="-326"/>
@@ -6212,26 +5351,12 @@
<translation>Hutsegitea <b>%1</b> makina birtualaren ezarpenak<b><nobr>%2</nobr></b>-an gordetzerakoan.</translation>
</message>
<message>
- <source>Failed to load the settings of the virtual machine <b>%1</b> from <b><nobr>%2</nobr></b>.</source>
- <translation type="obsolete">Hutsegitea <b>%1</b> makina birtualaren ezarpenak<b><nobr>%2</nobr></b>-tik gertatzerakoan.</translation>
- </message>
- <message>
<location line="-468"/>
<source>Discard</source>
<comment>saved state</comment>
<translation>Baztertu</translation>
</message>
<message>
- <source>Download</source>
- <comment>additions</comment>
- <translation type="obsolete">Jeitsi</translation>
- </message>
- <message>
- <source>Mount</source>
- <comment>additions</comment>
- <translation type="obsolete">Osatu</translation>
- </message>
- <message>
<location line="+1125"/>
<location filename="../src/globals/UIPopupCenter.cpp" line="-49"/>
<source><p>The host key is currently defined as <b>%1</b>.</p></source>
@@ -6251,16 +5376,6 @@
<translation>Egiaztatu</translation>
</message>
<message>
- <source>Switch</source>
- <comment>fullscreen</comment>
- <translation type="obsolete">Aldatu</translation>
- </message>
- <message>
- <source>Switch</source>
- <comment>seamless</comment>
- <translation type="obsolete">Aldatu</translation>
- </message>
- <message>
<location line="+23"/>
<source>Reset</source>
<comment>machine</comment>
@@ -6281,12 +5396,12 @@
<message>
<location line="+439"/>
<source><p>Could not enter seamless mode due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da irudizko modura sartu gonbidatuan ez dagoela nahikoa bideo oroimen.</p><p>Makina birtuala itxuratu behar duzu gutxienez<b>%1</b> bideo oroimen izateko.</p></translation>
</message>
<message>
<location line="-11"/>
<source><p>Could not switch the guest display to fullscreen mode due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch to fullscreen mode anyway or press <b>Cancel</b> to cancel the operation.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da gonbidatu ikusleihoa ikusleiho-osora aldatu ez dagoelako nahikoa bideo oroimen gonbidatuan.</p><p>Makina birtuala itxuratu behar duzu gutxienez <b>%1</b> bideo oroimen izateko.</p>><p>Sakatu <b>Ezikusi</b> horrela ere ikusleiho-osora aldatzeko edo sakatu <b>Ezeztatu</b> eragiketa ezeztatzeko.</p></translation>
</message>
<message>
<location line="+147"/>
@@ -6296,17 +5411,17 @@
<message>
<location line="-211"/>
<source><p>You have <b>clicked the mouse</b> inside the Virtual Machine display or pressed the <b>host key</b>. This will cause the Virtual Machine to <b>capture</b> the host mouse pointer (only if the mouse pointer integration is not currently supported by the guest OS) and the keyboard, which will make them unavailable to other applications running on your host machine.</p><p>You can press the <b>host key</b> at [...]
- <translation type="unfinished"></translation>
+ <translation><p>Makina Birtualaren erakusleiho barnean <b>sagua klikatuta</b> edo <b>hostalari tekla</b> sakatuta duzu. Honek Makina Birtualak hostalariaren sagu punta (sagu punta baterapena sostengatua ez badago gonbidatu SE-n) eta teklatua, zure hostalari makinan ekinean dauden beste aplikazioentzat eskuraezina egingo duena <b>hartzea</b> eragiten du.</p><p><b>Hostalari tekla</b> sakatu dezakezu edonoiz teklatua [...]
</message>
<message>
<location filename="../src/globals/UIPopupCenter.cpp" line="-13"/>
<source><p>You have the <b>Auto capture keyboard</b> option turned on. This will cause the Virtual Machine to automatically <b>capture</b> the keyboard every time the VM window is activated and make it unavailable to other applications running on your host machine: when the keyboard is captured, all keystrokes (including system ones like Alt-Tab) will be directed to the VM.</p><p>You can press the <b>host key</b> at any time t [...]
- <translation type="unfinished"></translation>
+ <translation><p><b>Berez hartu teklatua</b> aukera piztuta duzu. Honek Makina Birtualak teklatua berezgaitasunez <b>hartzea</b> eragiten du MB-ren leihoa gaitua den bakoitzean eta eskuraezina egiten du zure hostalari makinan ekinean dauden beste aplikazioentzat: teklatua hartzen denean, teklatuko eragiketa guztiak (sistemaren Alt-Tab bezalakoak barne) MB-ra zuzenduko dira.</p><p><b>Hostalari tekla</b> sakatu dezakezu edonoiz t [...]
</message>
<message>
<location line="+24"/>
<source><p>The Virtual Machine reports that the guest OS supports <b>mouse pointer integration</b>. This means that you do not need to <i>capture</i> the mouse pointer to be able to use it in your guest OS -- all mouse actions you perform when the mouse pointer is over the Virtual Machine's display are directly sent to the guest OS. If the mouse is currently captured, it will be automatically uncaptured.</p><p>The mouse icon on the s [...]
- <translation type="unfinished"></translation>
+ <translation><p><p>Makina Birtualak jakinarazi du gonbidatu SE-k ez duela <b>sagu punta baterapena</b> sostengatzen. Honek esanahi du sagu punta <i>hartu</i> egin behar duzula gonbidatu SE-ren barnean erabiltzeko.</p> -- Makina Birtualaren erakusleihoaren gainean egiten dituzun sagu punta ekintza guztiak zuzenean bidaltzen dira gonbidatu SE-ra. Sagua hartuta badago, berezgaitasunez deshartuko da.</p><p>Sagu ikurra egoera barr [...]
</message>
<message>
<location filename="../src/globals/UIMessageCenter.cpp" line="+201"/>
@@ -6320,10 +5435,6 @@
<translation>Argitaratu</translation>
</message>
<message>
- <source><p>Are you sure you want to remove the %1 <nobr><b>%2</b></nobr> from the list of known media?</p></source>
- <translation type="obsolete"><p>Zihur zaude %1 <nobr><b>%2</b></nobr> multimedia ezagunen zerrendatik kentzea nahi duzula?</p></translation>
- </message>
- <message>
<location line="+51"/>
<source>Remove</source>
<comment>medium</comment>
@@ -6332,12 +5443,12 @@
<message>
<location line="+226"/>
<source><p>The hard disk storage unit at location <b>%1</b> already exists. You cannot create a new virtual hard disk that uses this location because it can be already used by another virtual hard disk.</p><p>Please specify a different location.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Jadanik badago <b>%1</b> diska gogor biltegi unitate kokalekua. Ezin duzu diska gogor birtual berri bat sortu kokaleku hau erabiliz jadanik beste diska gogor birtual batek erabili ahal dezakeelako.</p><p>Mesedez adierazi beste kokaleku bat.</p></translation>
</message>
<message>
<location line="-220"/>
<source><p>Do you want to delete the storage unit of the hard disk <nobr><b>%1</b></nobr>?</p><p>If you select <b>Delete</b> then the specified storage unit will be permanently deleted. This operation <b>cannot be undone</b>.</p><p>If you select <b>Keep</b> then the hard disk will be only removed from the list of known hard disks, but the storage unit will be left untouched which makes it po [...]
- <translation type="unfinished"></translation>
+ <translation><p>Ezabatzea nahi duzu <nobr><b>%1</b></nobr> diska gogor birtualaren biltegiratze unitatea?</p><p><b>Ezabatu</b> hautatzen baduzu adierazitako biltegiratze unitatea betirako ezabatuko da. Eragiketa hau <b>ezin da desegin</b>.</p><p><b>Heutsi</b> hautatzen baduzu diska gogorra diska gogor ezagunen zerrendatik besterik ez da kenduko, baina biltegiratze unitateak ikutugabe jarrait [...]
</message>
<message>
<location line="+11"/>
@@ -6365,21 +5476,9 @@
<translation>Hutsegitea diska gogor biltegia sortzerakoan <nobr><b>%1</b>.</nobr></translation>
</message>
<message>
- <source>Failed to open the %1 <nobr><b>%2</b></nobr>.</source>
- <translation type="obsolete">Hutsegitea %1 irekitzerakoan <nobr><b>%2</b></nobr>.</translation>
- </message>
- <message>
- <source>Failed to close the %1 <nobr><b>%2</b></nobr>.</source>
- <translation type="obsolete">Hutsegitea %1 isterakoan <nobr><b>%2</b></nobr>.</translation>
- </message>
- <message>
- <source><p>Failed to connect to the VirtualBox online registration service due to the following error:</p><p><b>%1</b></p></source>
- <translation type="obsolete"><p>Hutsegitea VirtualBox-en onlineko erregistrazio zerbitzura elkartzerakoan hurrengo akatsagaitik: </p><p><b>%1</b></p></translation>
- </message>
- <message>
<location line="+211"/>
<source><p>A critical error has occurred while running the virtual machine and the machine execution has been stopped.</p><p>For help, please see the Community section on <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> or your support contract. Please provide the contents of the log file <tt>VBox.log</tt> and the image file <tt>VBox.png</tt>, which you can find in the <nobr><b>%1</b></nob [...]
- <translation type="unfinished"></translation>
+ <translation><p>Akats larri bat gertatu da makina birtualaren jardunean eta makinaren exekuzioa gelditu egin da.</p><p>Laguntza lortzeko, mesedez ikusi Herkidegoa atala <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> edo zure sostengu itunean. Mesedez hornitu <tt>VBox.log</tt> ohar agiriaren edukiak eta <tt>VBox.png</tt> irudi agiria, hauek makina birtualaren <nobr><b>%1</b></nobr> zuz [...]
</message>
<message>
<location line="+621"/>
@@ -6394,12 +5493,12 @@
<message>
<location filename="../src/globals/UIPopupCenter.cpp" line="-31"/>
<source>You are trying to shut down the guest with the ACPI power button. This is currently not possible because the guest does not support software shutdown.</source>
- <translation type="unfinished"></translation>
+ <translation>Gonbidatua ACPI indar botoiarekin itzaltzen saiatzen ari zara. Hau oraingoz ezinezkoa da gonbidatuak ez duelako software itzalketa sostengatzen.</translation>
</message>
<message>
<location filename="../src/globals/UIMessageCenter.cpp" line="+1363"/>
<source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Your 64-bit guest will fail to detect a 64-bit CPU and will not be able to boot.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>VT-x/AMD-V hardware bizkorpena gaitu egin da, baina ez dago eraginkor. Zure 64-biteko gonbidatuak huts egingo du 64-bit CPU bat atzematerakoan eta ez da abiatzeko gai izango.</p><p>Mesedez zihurtatu VT-x/AMD-V egoki gaituta duzula zure hostalari ordenagailuaren BIOS-ean.</p></translation>
</message>
<message>
<location line="+6"/>
@@ -6427,17 +5526,9 @@
<translation>Ezeztatu</translation>
</message>
<message>
- <source>Failed to create the host-only network interface.</source>
- <translation type="obsolete">Hutsegitea hostalaria-bakarrik sare interfazea sortzerakoan.</translation>
- </message>
- <message>
- <source>Failed to open appliance.</source>
- <translation type="obsolete">Hutsegitea makina birtuala irekitzerakoan.</translation>
- </message>
- <message>
<location line="+737"/>
<source>Failed to open/interpret appliance <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> gailua ireki/interpretatzerakoan.</translation>
</message>
<message>
<location line="+8"/>
@@ -6445,18 +5536,10 @@
<translation>Hutsegitea makina birtuala inportatzerakoan <b>%1</b>.</translation>
</message>
<message>
- <source>Failed to create appliance.</source>
- <translation type="obsolete">Hutsegitea makina birtuala sortzerakoan.</translation>
- </message>
- <message>
<location line="+36"/>
<location line="+8"/>
<source>Failed to prepare the export of the appliance <b>%1</b>.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Failed to create an appliance.</source>
- <translation type="obsolete">Hutsegitea makina birtual bat sortzerakoan.</translation>
+ <translation>Hutsegitea <b>%1</b> gailuaren esportazioa gertatzerakoan.</translation>
</message>
<message>
<location line="+8"/>
@@ -6466,7 +5549,7 @@
<message>
<location line="-700"/>
<source><p>Deleting this host-only network will remove the host-only interface this network is based on. Do you want to remove the (host-only network) interface <nobr><b>%1</b>?</nobr></p><p><b>Note:</b> this interface may be in use by one or more virtual network adapters belonging to one of your VMs. After it is removed, these adapters will no longer be usable until you correct their settings by either choosing a different in [...]
- <translation type="unfinished"></translation>
+ <translation><p>Hostalaria-bakarrik sare hau ezabatzeak sare honek ohinarri duen hostalaria-bakarrik interfazea kenduko du. <nobr><b>%1</b> (hostalaria-bakarrik sarea) interfazea kentzea nahi duzu?</nobr></p><p><b>Oharra:</b> egokitzaile birtual bat baino gehiago egon daiteke interfaze hau erabiltzen zure MB-etan. Kendu ondoren, egokitzaile hauek ezingo dira gehiago erabili beren ezarpenak zuzentzen dituzun arte beste interfaz [...]
</message>
<message>
<location line="+1416"/>
@@ -6476,15 +5559,7 @@
<message>
<location line="-561"/>
<source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Certain guests (e.g. OS/2 and QNX) require this feature.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p>Invalid e-mail address or password specified.</p></source>
- <translation type="obsolete"><p>Post@ helbide edo sarhitz okerra adierazi da.</p></translation>
- </message>
- <message>
- <source><p>Failed to register the VirtualBox product.</p><p>%1</p></source>
- <translation type="obsolete"><p>Hutsegitea VirtualBox produktua erregistratzerakoan.</p><p>%1</p></translation>
+ <translation><p>VT-x/AMD-V hardware bizkorpena gaitu egin da, baina ez dago eraginkor. Zenbait gonbidatuk (adib. OS/2 eta QNX) ezaugarri hau behar dute.</p><p>Mesedez zihurtatu VT-x/AMD-V egoki gaituta duzula zure hostalari ordenagailuaren BIOS-ean.</p></translation>
</message>
<message>
<location line="-199"/>
@@ -6499,12 +5574,12 @@
<message>
<location line="-1208"/>
<source>You seem to have the USBFS filesystem mounted at /sys/bus/usb/drivers. We strongly recommend that you change this, as it is a severe mis-configuration of your system which could cause USB devices to fail in unexpected ways.</source>
- <translation type="unfinished"></translation>
+ <translation>Dirudienez USBFS agiri-sistema duzu muntatuta honela: /sys/bus/usb/drivers. Hau aldatzea gomendatzen dizugu, zure sistemaren itxurapen-oker larria denez eta USB gailuek ustekabeko moduan huts egitea eragin dezakeelako.</translation>
</message>
<message>
<location line="+10"/>
<source><p>Cannot start the VirtualBox Manager due to local restrictions.</p><p>The application will now terminate.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da VirtualBox Kudeatzailea abiarazi tokiko murrizketengaitik.</p><p>Aplikazioak orain amaitu egingo du.</p></translation>
</message>
<message>
<location line="+14"/>
@@ -6514,17 +5589,17 @@
<message>
<location line="+35"/>
<source><p>Could not find a language file for the language <b>%1</b> in the directory <b><nobr>%2</nobr></b>.</p><p>The language will be temporarily reset to the system default language. Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da <b>%1</b> hizkuntzarako hizkuntza agiria aurkitu <b><nobr>%2</nobr></b> zuzenbidean.</p><p>Hizkuntza aldibaterako sistemaren berezko hizkuntzan berrezarriko da. Mesedez joan <b>Hobespenak</b> leihora VirtualBox Kudeatzaile leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean badagoen hizkuntzetako bat.</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>Could not load the language file <b><nobr>%1</nobr></b>. <p>The language will be temporarily reset to English (built-in). Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da <b><nobr>%1</nobr></b> hizkuntza agiria gertatu. <p>Hizkuntza aldibaterako Ingeleran (barne-eraikia) berrezarriko da. Mesedez joan <b>Hobespenak</b> leihora VirtualBox Kudeatzaile leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean badagoen hizkuntzetako bat.</p></translation>
</message>
<message>
<location line="+36"/>
<source>There is no virtual machine with the identifier <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Ez dago makina birtualik <b>%1</b> ezagutarazlearekin.</translation>
</message>
<message>
<location line="+31"/>
@@ -6534,7 +5609,7 @@
<message>
<location line="+171"/>
<source><p>One or more virtual hard disks, CD/DVD or floppy disk image files are not currently accessible. As a result, you will not be able to operate virtual machines that use these files until they become accessible later.</p><p>Press <b>Check</b> to open the Virtual Media Manager window and see which files are inaccessible, or press <b>Ignore</b> to ignore this message.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Diska gogor birtual, CD/DVD edo diskete irudi agiri bat edo gehiago ez daude eskuragarri. Ondorioz, ezingo duzu agiri hauek erabiltzen dituzten makina birtualekin jardun geroago eskuragarri egon arte.</p><p>Sakatu <b>Egiaztatu</b> Media Birtual Kudeatzailea leihoa irekitzeko eta agiri eskuragarriak ikusteko edo sakatu <b>Ezikusi</b> mezu hau ezikusteko.</p></translation>
</message>
<message>
<location line="+8"/>
@@ -6542,7 +5617,7 @@
<location line="+139"/>
<location line="+21"/>
<source>Ignore</source>
- <translation type="unfinished">Ezikusi</translation>
+ <translation>Ezikusi</translation>
</message>
<message>
<location line="-1094"/>
@@ -6553,7 +5628,7 @@
<message>
<location line="+6"/>
<source><p>Deleting the snapshot will cause the state information saved in it to be lost, and disk data spread over several image files that VirtualBox has created together with the snapshot will be merged into one file. This can be a lengthy process, and the information in the snapshot cannot be recovered.</p></p>Are you sure you want to delete the selected snapshot <b>%1</b>?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Berehalakoa ezabatzeak bertan gordetako egoera argibideak galtzea eragingo du, eta VirtualBox-ek berehalakoarekin batera sortu dituen irudi agiri ugarietan dauden biltegiratze datu barreiatuak agiri batean batuko dira. Hau prozesu luzea izan daiteke, eta berehalakoan dauden argibideak ezingo dira berreskuratu. </p></p>Zihur zaude hautaturiko <b>%1</b> berehalakoa ezabatzea nahi duzula?</p></translation>
</message>
<message>
<location line="+6"/>
@@ -6565,21 +5640,13 @@
<location line="+22"/>
<location line="+9"/>
<source>Failed to restore the snapshot <b>%1</b> of the virtual machine <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%2</b> makina birtualaren <b>%1</b> berehalakoa leheneratzerakoan.</translation>
</message>
<message>
<location line="+9"/>
<location line="+8"/>
<source>Failed to delete the snapshot <b>%1</b> of the virtual machine <b>%2</b>.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Unable to mount the %1 <nobr><b>%2</b></nobr> on the machine <b>%3</b>.</source>
- <translation type="obsolete">Ezinezkoa %1 osatzea <nobr><b>%2</b></nobr> <b>%3</b> makinan.</translation>
- </message>
- <message>
- <source>Unable to unmount the %1 <nobr><b>%2</b></nobr> from the machine <b>%3</b>.</source>
- <translation type="obsolete">Ezinezkoa %1 osatzea <nobr><b>%2</b></nobr> <b>%3</b> makinatik.</translation>
+ <translation>Hutsegitea <b>%2</b> makina birtualaren <b>%1</b> berehalakoa ezabatzerakoan.</translation>
</message>
<message>
<location line="+482"/>
@@ -6587,40 +5654,6 @@
<translation>Behartu Desosatzea</translation>
</message>
<message>
- <source>E&xit</source>
- <comment>warnAboutSettingsAutoConversion message box</comment>
- <translation type="obsolete">I&rten</translation>
- </message>
- <message>
- <source>hard disk</source>
- <comment>failed to mount ...</comment>
- <translation type="obsolete">diska gogorra</translation>
- </message>
- <message>
- <source>CD/DVD</source>
- <comment>failed to mount ... host-drive</comment>
- <translation type="obsolete">CD/DVD</translation>
- </message>
- <message>
- <source>CD/DVD image</source>
- <comment>failed to mount ...</comment>
- <translation type="obsolete">CD/DVD irudia</translation>
- </message>
- <message>
- <source>floppy</source>
- <comment>failed to mount ... host-drive</comment>
- <translation type="obsolete">disketea</translation>
- </message>
- <message>
- <source>floppy image</source>
- <comment>failed to mount ...</comment>
- <translation type="obsolete">diskete irudia</translation>
- </message>
- <message>
- <source><p>Are you sure you want to delete the CD/DVD-ROM device?</p><p>You will not be able to mount any CDs or ISO images or install the Guest Additions without it!</p></source>
- <translation type="obsolete"><p>Zihur zaude CD/DVD-ROM gailua ezabatzea nahi duzula?</p><p>Ezingo duzu CD edo ISO irudirik osatu edo Gonbidatu Gehigarririk ezarri bera gabe!</p></translation>
- </message>
- <message>
<location line="-302"/>
<source>&Remove</source>
<comment>medium</comment>
@@ -6639,29 +5672,17 @@
<message>
<location line="-938"/>
<source><p>Deleting the snapshot %1 will temporarily need more disk space. In the worst case the size of image %2 will grow by %3, however on this filesystem there is only %4 free.</p><p>Running out of disk space during the merge operation can result in corruption of the image and the VM configuration, i.e. loss of the VM and its data.</p><p>You may continue with deleting the snapshot at your own risk.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>%1 berehalako ezabatzeak biltegiratze toki gehiago beharko du aldibaterako. Kasu okerrenean %2 irudiaren neurria %3 haziko da, horrela ere agiri-sistema honek %4 besterik ez ditu aske.</p><p>Batze eragiketan zehar biltegiratze tokirik gabe gelditzeak irudiaren eta MB-ren itxurapena hondatzea eragin dezake, adib. MB eta bere datuak galtzea.</p><p>Berehalakoaren ezabatzearekin jarraitu dezakezu zeure arriskupean.</p></translation>
</message>
<message>
<location line="+1070"/>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ezin da gonbidatu ikusleihoa hostalari ikusleihora aldatu ez dagoelako nahikoa bideo oroimen gonbidatuan.</p><p>Makina birtuala itxuratu behar duzu gutxienez <b>%1</b> bideo oroimen izateko.</p></translation>
</message>
<message>
<location line="-11"/>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch the screen anyway or press <b>Cancel</b> to cancel the operation.</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p>Are you sure you want to download the VirtualBox User Manual from <nobr><a href="%1">%2</a></nobr> (size %3 bytes)?</p></source>
- <translation type="obsolete"><p>Zihur zaude VirtualBox Erabiltzaile Eskuliburua jeistea nahi duzula hemendik, <nobr><a href="%1">%2</a></nobr> (neurria %3 byte)?</p></translation>
- </message>
- <message>
- <source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%2</a></nobr> and saved locally as <nobr><b>%3</b>.</nobr></p></source>
- <translation type="obsolete"><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%2</a></nobr> eta tokian gorde da honela <nobr><b>%3</b>.</nobr></p></translation>
- </message>
- <message>
- <source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%2</a></nobr> but can't be saved locally as <nobr><b>%3</b>.</nobr></p><p>Please choose another location for that file.</p></source>
- <translation type="obsolete"><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%2</a></nobr>baina ezin da tokian gorde honela <nobr><b>%3</b>.</nobr></p><p>Mesedez hautatu beste kokaleku bat agiriarentzat.</p></translation>
+ <translation><p>Ezin da gonbidatu ikusleihoa hostalari ikusleihora aldatu ez dagoelako nahikoa bideo oroimen gonbidatuan.</p><p>Makina birtuala itxuratu behar duzu gutxienez <b>%1</b> bideo oroimen izateko.</p>><p>Sakatu <b>Ezikusi</b> horrela ere ikusleihoa aldatzeko edo sakatu <b>Ezeztatu</b> eragiketa ezeztatzeko.</p></translation>
</message>
<message>
<location line="-1376"/>
@@ -6694,58 +5715,38 @@
<message>
<location line="+112"/>
<source><p>You are about to add a virtual hard disk to controller <b>%1</b>.</p><p>Would you like to create a new, empty file to hold the disk contents or select an existing one?</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Create &new disk</source>
- <comment>add attachment routine</comment>
- <translation type="obsolete">&Sortu diska berria</translation>
- </message>
- <message>
- <source>&Choose existing disk</source>
- <comment>add attachment routine</comment>
- <translation type="obsolete">&Hautatu badagoen diska</translation>
+ <translation><p>Diska gogor birtual bat gehitzear zaude <b>%1</b> kontrolatzailera.</p><p>Berri bat sortzea, agiri huts bat diskaren edukiari heusteko edo badagoen bat hautatzea nahi duzu?</p></translation>
</message>
<message>
<location line="+10"/>
<source><p>You are about to add a new CD/DVD drive to controller <b>%1</b>.</p><p>Would you like to choose a virtual CD/DVD disk to put in the drive or to leave it empty for now?</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>&Choose disk</source>
- <comment>add attachment routine</comment>
- <translation type="obsolete">&Hautatu diska</translation>
- </message>
- <message>
- <source>Leave &empty</source>
- <comment>add attachment routine</comment>
- <translation type="obsolete">Utzi &hutsik</translation>
+ <translation><p>CD/DVD gidagailu berri bat gehitzear zaude <b>%1</b> kontrolatzailera.</p><p>Diska optiko birtual bat hautatzea nahi duzu diskan jartzeko edo oraingoz hutsik uztea nahi duzu?</p></translation>
</message>
<message>
<location line="+11"/>
<source><p>You are about to add a new floppy drive to controller <b>%1</b>.</p><p>Would you like to choose a virtual floppy disk to put in the drive or to leave it empty for now?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Diskete gehitzear zaude <b>%1</b> kontrolatzailera.</p><p>Diskete birtual bat hautatzea nahi duzu diskan jartzeko edo oraingoz hutsik uztea nahi duzu?</p></translation>
</message>
<message>
<location line="+247"/>
<source>Failed to detach the hard disk (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) diska gogorra <b>%3</b> makinaren <i>%2</i> eslotetik deseranstearakoan.</translation>
</message>
<message>
<location line="+6"/>
<source>Failed to detach the CD/DVD device (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) CD/DVD gailua <b>%3</b> makinaren <i>%2</i> eslotetik deseranstearakoan.</translation>
</message>
<message>
<location line="+6"/>
<source>Failed to detach the floppy device (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) disketea <b>%3</b> makinaren <i>%2</i> eslotetik deseranstearakoan.</translation>
</message>
<message>
<location line="+952"/>
<location line="+8"/>
<source>Failed to install the Extension Pack <b>%1</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea <b>%1</b> Hedapen Paketea ezartzerakoan.</translation>
</message>
<message>
<location line="+8"/>
@@ -6761,48 +5762,43 @@
<message>
<location line="-1138"/>
<source>The current port forwarding rules are not valid. None of the host or guest port values may be set to zero.</source>
- <translation type="unfinished"></translation>
+ <translation>Oraingo berbidalketa ataka arauak ez dira baliozkoak. Hostalari edo gonbidatu ataka balioetako bat ere ezin daiteke hutsean ezarri.</translation>
</message>
<message>
<location line="+7"/>
<source><p>There are unsaved changes in the port forwarding configuration.</p><p>If you proceed your changes will be discarded.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Gorde gabeko aldaketak daude berbidalketa ataka itxurapenean.</p><p>Jarraitzen baduzu aldaketak baztertu egingo dira.</p></translation>
</message>
<message>
<location line="-33"/>
<source>Failed to attach the hard disk (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) diska gogorra <b>%3</b> makinaren <i>%2</i> eslotera eranstearakoan.</translation>
</message>
<message>
<location line="+6"/>
<source>Failed to attach the CD/DVD device (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) CD/DVD gailua <b>%3</b> makinaren <i>%2</i> eslotera eranstearakoan.</translation>
</message>
<message>
<location line="+6"/>
<source>Failed to attach the floppy device (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea (<nobr><b>%1</b></nobr>) disketea <b>%3</b> makinaren <i>%2</i> eslotera eranstearakoan.</translation>
</message>
<message>
<location line="+144"/>
<location line="+8"/>
<source><p>Note that the storage unit of this medium will not be deleted and that it will be possible to use it later again.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Ohartu medio honen biltegi unitatea ez dela ezabatuko eta berriro erabili ahal izango dela geroago.</p></translation>
</message>
<message>
<location line="+589"/>
<source><p>The virtual machine window will be now switched to <b>fullscreen</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in fullscreen mode. You can access it by pressing <b>Host+Home</b>.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Makina birtualaren leihoa orain <b>ikusleiho-osoko</b> modura aldatuko da. Leihotu modura itzuli zaitezke <b>%1</b> sakatuz.</p><p>Ohartu <i>Host</i> tekla <b>%2</b> bezala zehaztua dagoela.</p><p>Ohartu ere menu barra nagusia ezkutatu egiten dela ikusleiho-osoko moduan. Bertara <b>Host+Home</b> sakatuz sartu zaitezke.</p></translation>
</message>
<message>
<location line="+13"/>
<source><p>The virtual machine window will be now switched to <b>Seamless</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in seamless mode. You can access it by pressing <b>Host+Home</b>.</p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Switch</source>
- <comment>scale</comment>
- <translation type="obsolete">Aldatu</translation>
+ <translation><p>Makina birtualaren leihoa orain <b>Irudizkoa</b> modura aldatuko da. Leihotu modura itzuli zaitezke <b>%1</b> sakatuz.</p><p>Ohartu <i>Host</i> tekla <b>%2</b> bezala zehaztua dagoela.</p><p>Ohartu ere menu barra nagusia ezkutatu egiten dela irudizko moduan. Bertara <b>Host+Home</b> sakatuz sartu zaitezke.</p></translation>
</message>
<message>
<location line="+404"/>
@@ -6813,16 +5809,12 @@
<message>
<location line="-92"/>
<source><p>You are about to install a VirtualBox extension pack. Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%1< [...]
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>&Install</source>
- <translation type="obsolete">&Ezarri</translation>
+ <translation><p>VirtualBox hedapen pakete bat ezartzear zaude. Hedapen paketeek VirtualBox-en eginkizunak osatzen dituzte eta zure sistemarentzat potentzialki kaltergarria izan daitekeen sistema mailako softwarea eduki dezakete. Mesedez berrikusi azpiko azalpena eta jarraitu hedapen paketea iturri fidagarri batetik lortu baduzu bakarrik.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td>< [...]
</message>
<message>
<location line="+19"/>
<source>Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</source>
- <translation type="unfinished"></translation>
+ <translation>Hedapen paketeek VirtualBox-en eginkizunak osatzen dituzte eta zure sistemarentzat potentzialki kaltergarria izan daitekeen sistema mailako softwarea eduki dezakete. Mesedez berrikusi azpiko azalpena eta jarraitu hedapen paketea iturri fidagarri batetik lortu baduzu bakarrik.</translation>
</message>
<message>
<location line="+14"/>
@@ -6903,11 +5895,7 @@
<message>
<location line="-674"/>
<source>Create a snapshot of the current machine state</source>
- <translation>Sortu makinaren oraingo egoeraren argazki bat</translation>
- </message>
- <message>
- <source>Sorry, some generic error happens.</source>
- <translation type="obsolete">Barkatu, zenbati akats generiko gertatu dira.</translation>
+ <translation>Sortu makinaren oraingo egoeraren berehalako bat</translation>
</message>
<message>
<location line="+1799"/>
@@ -6940,20 +5928,11 @@
<translation>Ezin da<b>%1</b> izeneko berehalakoa aurkitu.</translation>
</message>
<message>
- <source><p>Failed to save the downloaded file as <nobr><b>%1</b>.</nobr></p></source>
- <translation type="obsolete"><p>Hutsegitea jeitsitako agiria gordetzerakoan,<nobr><b>%1</b>.</nobr></p></translation>
- </message>
- <message>
<location line="+503"/>
<source><p>You have an old version (%1) of the <b><nobr>%2</nobr></b> installed.</p><p>Do you wish to download latest one from the Internet?</p></source>
<translation><p><b><nobr>%2</nobr></b>-ren bertsio zahar bat (%1) duzu ezarrita.</p><p>Nahi duzu azkenengoa Internetetik jeistea?</p></translation>
</message>
<message>
- <source>Download</source>
- <comment>extension pack</comment>
- <translation type="obsolete">Jeitsi</translation>
- </message>
- <message>
<location line="+10"/>
<source><p>Are you sure you want to download the <b><nobr>%1</nobr></b> from <nobr><a href="%2">%2</a></nobr> (size %3 bytes)?</p></source>
<translation><p>Zihur zaude <b><nobr>%1</nobr></b> <nobr><a href="%2">%2</a></nobr>-tik jeistea nahi duzula (neurria %3 byte)?</p></translation>
@@ -6981,14 +5960,9 @@
<translation><p><b><nobr>%2</nobr></b>-ren %1 bertsioa duzu ezarrita.</p><p> Hedapen pakete honen %3 bertsioa jeitsi eta ezarri behar duzu Oracle-tik!</p></translation>
</message>
<message>
- <source>Ok</source>
- <comment>extension pack</comment>
- <translation type="obsolete">Ongi</translation>
- </message>
- <message>
<location line="-1629"/>
<source><p>Failed to initialize COM because the VirtualBox global configuration directory <b><nobr>%1</nobr></b> is not accessible. Please check the permissions of this directory and of its parent directory.</p><p>The application will now terminate.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Hutsegitea COM abiarazterakoan <b><nobr>%1</nobr></b> VirtualBox-en itxurapen orokorraren zuzenbidea ez dagoelako eskuragarri. Mesedez egiaztatu zuzenbide honen eta bere gaineko zuzenbidearen baimenak.</p><p>Aplikazioak orain amaitu egingo du.</p></translation>
</message>
<message>
<location line="+169"/>
@@ -7003,12 +5977,12 @@
<message>
<location line="+5"/>
<source><p>You are about to remove following virtual machines from the machine list:</p><p>%1</p><p>Would you like to delete the files containing the virtual machine from your hard disk as well? Doing this will also remove the files containing the machine's virtual hard disks if they are not in use by another machine.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Hurrengo makina birtualak kentzear zaude makina zerrendatik:</p><p>%1</p><p>Makina birtuala duten agiriak zure diska gogorretik ere ezabatzea nahi dituzu? Hau egiteak makina birtualaren diska gogorrak dituzten agiriak ere kenduko ditu ez baditu erabiltzen beste makina batek.</p></translation>
</message>
<message>
<location line="+6"/>
<source><p>You are about to remove following virtual machines from the machine list:</p><p>%1</p><p>Would you like to delete the files containing the virtual machine from your hard disk as well?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Hurrengo makina birtualak kentzear zaude makina zerrendatik:</p><p>%1</p><p>Makina birtuala duten agiriak zure diska gogorretik ere ezabatzea nahi dituzu?</p></translation>
</message>
<message>
<location line="+1374"/>
@@ -7040,43 +6014,43 @@
<message>
<location line="-86"/>
<source>You are about to create a new virtual machine without a hard drive. You will not be able to install an operating system on the machine until you add one. In the mean time you will only be able to start the machine using a virtual optical disk or from the network.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtual berri bat diska gogor bat gabe sortzear zaude. Ezingo duzu sistema eragilerik ezarri makinan bat gehitu arte. Bitartean makina diska optiko birtual bat erabiliz edo saretik bakarrik abiatu ahalko duzu.</translation>
</message>
<message>
<location line="+866"/>
<location line="+7"/>
<source>Failed to drop data.</source>
- <translation type="unfinished"></translation>
+ <translation>Hutsegitea datuak erortzeerakoan.</translation>
</message>
<message>
<location line="-1625"/>
<source><p>Are you sure you want to discard the saved state of the following virtual machines?</p><p><b>%1</b></p><p>This operation is equivalent to resetting or powering off the machine without doing a proper shutdown of the guest OS.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude hurrengo makina birtualen gordetako egoera baztertzea nahi duzula?</p><p><b>%1</b></p><p>Eragiketa hau gonbidatu SE-ren itzaltze egoki bat egin gabe makina itzaltzea edo berrezartzearen baliokidea da.</p></translation>
</message>
<message>
<location line="+12"/>
<source><p>Do you really want to reset the following virtual machines?</p><p><b>%1</b></p><p>This will cause any unsaved data in applications running inside it to be lost.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Egitan nahi duzu hurrengo makina birtualak berrezartzea?</p><p><b>%1</b></p><p>Honek barnean lanean dauden aplikazioen gorde gabeko datu guztiak galtzea eraginbo du.</p></translation>
</message>
<message>
<location line="+11"/>
<source><p>Do you really want to send an ACPI shutdown signal to the following virtual machines?</p><p><b>%1</b></p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Egitan nahi duzu ACPI itzaltze seinale bat bidaltzea hurrengo makina birtualei?</p><p><b>%1</b></p></translation>
</message>
<message>
<location line="+10"/>
<source><p>Do you really want to power off the following virtual machines?</p><p><b>%1</b></p><p>This will cause any unsaved data in applications running inside it to be lost.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Egitan nahi duzu hurrengo makina birtualak itzaltzea?</p><p><b>%1</b></p><p>Honek barnean lanean dauden aplikazioen gorde gabeko datuak galtzea eragingo du.</p></translation>
</message>
<message>
<location line="-187"/>
<source><p>You are trying to move machine <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have sub-group <nobr><b>%1</b></nobr>.</p><p>Please resolve this name-conflict and try again.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><nobr><b>%1</b></nobr> makina <nobr><b>%2</b></nobr>-ra mugitzen saiatzen ari zara jadanik <nobr><b>%1</b></nobr> azpi-taldea duena.</p><p>Mesedez konpondu izen-gatazka hau eta saiatu berriro.</p></translation>
</message>
<message>
<location line="+9"/>
<source><p>You are trying to move group <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have another item with the same name.</p><p>Would you like to automatically rename it?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><nobr><b>%1</b></nobr> taldea <nobr><b>%2</b></nobr> taldera mugitzen saiatzen ari zara zeinak jadanik badu gai bat izen berarekin.</p><p>Nahi duzu berezgaitasunez berrizendatzea?</p></translation>
</message>
<message>
<location line="+5"/>
@@ -7086,12 +6060,12 @@
<message>
<location line="+249"/>
<source><p>You are about to restore snapshot <nobr><b>%1</b></nobr>.</p><p>You can create a snapshot of the current state of the virtual machine first by checking the box below; if you do not do this the current state will be permanently lost. Do you wish to proceed?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><nobr><b>%1</b></nobr> berehalakoa leheneratzear zaude.</p><p>Makina birtualaren oraingo egoeraren berehalako bat sortu dezakezu lehenik azpiko kutxatila hautatuz; ez baduzu hau egiten oraingo egoera betirako galduko da. Jarraitzea nahi duzu?</p></translation>
</message>
<message>
<location line="+11"/>
<source><p>Are you sure you want to restore snapshot <nobr><b>%1</b></nobr>?</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Zihur zaude <nobr><b>%1</b></nobr> berehalakoa leheneratzea nahi duzula?</p></translation>
</message>
<message>
<location line="-249"/>
@@ -7109,13 +6083,9 @@
<translation>Aldatu Sare Ezarpenak</translation>
</message>
<message>
- <source>Close Virtual Machine</source>
- <translation type="obsolete">Itxi Makina Birtuala</translation>
- </message>
- <message>
<location filename="../src/widgets/UIPopupPaneButtonPane.cpp" line="-1"/>
<source>Do not show this message again</source>
- <translation type="unfinished">Ez erakutsi mezu hau berriro</translation>
+ <translation>Ez erakutsi mezu hau berriro</translation>
</message>
</context>
<context>
@@ -7164,7 +6134,7 @@
<message>
<location line="+1"/>
<source>Holds the name of the virtual machine.</source>
- <translation type="unfinished"></translation>
+ <translation>Makina birtualaren izena zehazten du.</translation>
</message>
<message>
<location line="+2"/>
@@ -7177,27 +6147,15 @@
<translation>Makina birtual honetan ezartzeko asmoa duzun sistema eragile sendia hautatzen du (sistema eragile gonbidatua deitua).</translation>
</message>
<message>
- <source>Displays the name of the virtual machine.</source>
- <translation type="obsolete">Makina birtualaren izen erakusten du.</translation>
- </message>
- <message>
<location line="-4"/>
<source>&Type:</source>
<translation>&Mota:</translation>
</message>
<message>
- <source>Displays the operating system family that you plan to install into this virtual machine.</source>
- <translation type="obsolete">Makina birtual honetan ezartzeko asmoa duzun sistema eragile sendia erakusten du.</translation>
- </message>
- <message>
<location line="+3"/>
<source>&Version:</source>
<translation>&Bertsioa:</translation>
</message>
- <message>
- <source>Displays the operating system type that you plan to install into this virtual machine (called a guest operating system).</source>
- <translation type="obsolete">Makina birtual honetan ezartzeko asmoa duzun sistema eragile sendia erakusten du. (gonbidatu sistema eragilea deitua).</translation>
- </message>
</context>
<context>
<name>UINetworkManagerDialog</name>
@@ -7222,10 +6180,6 @@
<translation>Ezeztatu sare eragiketa gaitu guztiak</translation>
</message>
<message>
- <source>Error: %1.</source>
- <translation type="obsolete">Akatsa: %1.</translation>
- </message>
- <message>
<location filename="../src/net/UINetworkRequestWidget.cpp" line="+179"/>
<source>The network operation failed with the following error: %1.</source>
<translation>Sare eragiketak huts egin du hurrengo akatsarekin: %1.</translation>
@@ -7300,7 +6254,7 @@
<message>
<location line="+2"/>
<source>Unknown reason</source>
- <translation>Zergaitik ezezaguna</translation>
+ <translation>Zergaiti ezezaguna</translation>
</message>
</context>
<context>
@@ -7430,10 +6384,6 @@
<translation><i>Hautatu ezarpen kategoria bat ezkerreko zerrendatik eta mugitu sagua ezarpen gaien gainean argibide gehiago lortzeko.</i></translation>
</message>
<message>
- <source>On the <b>%1</b> page, %2</source>
- <translation type="obsolete"><b>%1</b> orrialdean, %2</translation>
- </message>
- <message>
<location filename="../src/settings/UISettingsDialog.cpp" line="+232"/>
<source>Invalid settings detected</source>
<translation>Ezarpen baliogabea atzeman da</translation>
@@ -7449,10 +6399,6 @@
<translation><b>%1: %2</b> orrialdea:</translation>
</message>
<message>
- <source>Non-optimal settings detected</source>
- <translation type="obsolete">Ezarpen ez-hoberena atzeman da</translation>
- </message>
- <message>
<location line="-56"/>
<source>Settings</source>
<translation>Ezarpenak</translation>
@@ -7481,10 +6427,6 @@
<translation>Hizkuntza</translation>
</message>
<message>
- <source>USB</source>
- <translation type="obsolete">USB</translation>
- </message>
- <message>
<location line="+6"/>
<source>Network</source>
<translation>Sarea</translation>
@@ -7525,7 +6467,7 @@
<message>
<location line="+3"/>
<source>Display</source>
- <translation>Erakutsi</translation>
+ <translation>Erakuspena</translation>
</message>
<message>
<location line="+3"/>
@@ -7682,7 +6624,7 @@
<message>
<location line="+4"/>
<source><p>Saves the current execution state of the virtual machine to the physical hard disk of the host PC.</p><p>Next time this machine is started, it will be restored from the saved state and continue execution from the same place you saved it at, which will let you continue your work immediately.</p><p>Note that saving the machine state may take a long time, depending on the guest operating system type and the amount of memory you assigned to th [...]
- <translation type="unfinished"></translation>
+ <translation><p>Makina birtualaren oraingo exekuzio egoera gordetzen du hostalari PC-aren diska gogor fisikoan.</p><p>Makina abiarazten den hurrengoan, gordetako egoeratik leheneratuko da eta exekuzioa jarraituko du gorde duzun toki berdinetik, zure lanarekin berehala jarraitzea ahalbidetuz.</p><p>Ohartu makinaren egoera gordetzeak luze hartu dezakeela, gonbidatuko sistema eragile motaren eta makina birtualari esleitutako oroimen kopuruaren arabera.& [...]
</message>
<message>
<location line="-1"/>
@@ -7692,7 +6634,7 @@
<message>
<location line="+7"/>
<source><p>Sends the ACPI Power Button press event to the virtual machine.</p><p>Normally, the guest operating system running inside the virtual machine will detect this event and perform a clean shutdown procedure. This is a recommended way to turn off the virtual machine because all applications running inside it will get a chance to save their data and state.</p><p>If the machine doesn't respond to this action then the guest operating system [...]
- <translation type="unfinished"></translation>
+ <translation><p>ACPI Indar Botoi sakatze gertaerak bildatzen ditu makina birtualera.</p><p>Arrunt, makina birtualaren barnean jarduten duen gonbidatu sistemak gertaera hau atzeman eta itzaltze prozedura garbi bat egingo du. Hau da makina birtuala itzaltzeko gomendatzen den bidea, horrela barnean jardunean dauden aplikazio guztiek beren datuak eta egoera gordetzeko aukera izango dutelako.</p><p>Makinak ez badio ekintza honi erantzuten gonbidatuko sist [...]
</message>
<message>
<location line="-1"/>
@@ -7702,7 +6644,7 @@
<message>
<location line="+9"/>
<source><p>Turns off the virtual machine.</p><p>Note that this action will stop machine execution immediately so that the guest operating system running inside it will not be able to perform a clean shutdown procedure which may result in <i>data loss</i> inside the virtual machine. Selecting this action is recommended only if the virtual machine does not respond to the <b>Send the shutdown signal</b> action.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Itzali makina birtuala.</p><p>Ohartu ekintza honek makinaren exekuzioa berehala geldiaraziko duela hortaz barnean jardunean dagoen gonbidatu sistema eragileak ezingo du itzaltze prozedura garbi bat egin eta <i>datu galera</i> bat gertatu daiteke makina birtualaren barnean. Ekintza hau makina birtualak <b>Bidali itzaltze seinalea</b> ekintzari ez badio erantzuten bakarrik hautatzea gomendatzen da.</p></translation>
</message>
<message>
<location line="-1"/>
@@ -7717,7 +6659,7 @@
<message>
<location line="+1"/>
<source><p>When checked, the machine will be returned to the state stored in the current snapshot after it is turned off. This is useful if you are sure that you want to discard the results of your last sessions and start again at that snapshot.</p></source>
- <translation><p>Hautatutakoan, makina oraingo berehalakoan biltegiratutako egoerara itzuliko da itzali ondoren. Hau erabilgarria da azken saioetako emaitzak baztertzeaz eta argazki berri bat hasteaz zihur bazaude.</p></translation>
+ <translation><p>Hautatutakoan, makina oraingo berehalakoan biltegiratutako egoerara itzuliko da itzali ondoren. Hau erabilgarria da azken saioetako emaitzak baztertzea eta berehalako berri bat hasteaz zihur bazaude.</p></translation>
</message>
<message>
<location line="-2"/>
@@ -7845,37 +6787,6 @@
</message>
</context>
<context>
- <name>UIVMPreviewWindow</name>
- <message>
- <source>Update Disabled</source>
- <translation type="obsolete">Eguneraketa ezgaituta</translation>
- </message>
- <message>
- <source>Every 0.5 s</source>
- <translation type="obsolete">0.5 seg-tik behin</translation>
- </message>
- <message>
- <source>Every 1 s</source>
- <translation type="obsolete">1 seg-tik behin</translation>
- </message>
- <message>
- <source>Every 2 s</source>
- <translation type="obsolete">2 seg-tik behin</translation>
- </message>
- <message>
- <source>Every 5 s</source>
- <translation type="obsolete">5 seg-tik behin</translation>
- </message>
- <message>
- <source>Every 10 s</source>
- <translation type="obsolete">10 seg-tik behin</translation>
- </message>
- <message>
- <source>No Preview</source>
- <translation type="obsolete">Ez dago Aurreikuspenik</translation>
- </message>
-</context>
-<context>
<name>UIWizard</name>
<message>
<location filename="../src/wizards/UIWizard.cpp" line="+123"/>
@@ -7950,7 +6861,7 @@
<message>
<location line="+2"/>
<source><p>You can also choose to <b>split</b> the hard drive file into several files of up to two gigabytes each. This is mainly useful if you wish to store the virtual machine on removable USB devices or old systems, some of which cannot handle very large files.</source>
- <translation><p>Hautatu dezakezu ere diska gogorra agiri anitzetan <b>banantzea</b> bakoitza bi gigabyte arte. Hau erabilgarria da nagusiki makina birtuala USB gailu kengarri batean edo sistema zaharretan biltegiratzea nahi baduzu, hauetako batzuek ezin dute agiri oso handika kudeatu.</translation>
+ <translation><p>Hautatu dezakezu ere diska gogorra agiri anitzetan <b>banantzea</b> bakoitza bi gigabyte arte. Hau erabilgarria da nagusiki makina birtuala USB gailu kengarri batean edo sistema zaharretan biltegiratzea nahi baduzu, hauetako batzuek ezin dituzte agiri oso handiak kudeatu.</translation>
</message>
<message>
<location line="+4"/>
@@ -8019,7 +6930,7 @@
<message>
<location filename="../src/wizards/clonevm/UIWizardCloneVM.cpp" line="+80"/>
<source>Linked Base for %1 and %2</source>
- <translation>Loturatutako Ohina %1 eta %2-rako</translation>
+ <translation>Loturiko Ohina %1 eta %2-rako</translation>
</message>
<message>
<location line="+85"/>
@@ -8045,7 +6956,7 @@
<message>
<location line="+3"/>
<source><p>Please choose a name for the new virtual machine. The new machine will be a clone of the machine <b>%1</b>.</p></source>
- <translation><p>Mesedez hautatu makina birtual berriarentzako izen bat. Makina berria <b>%1</b> makinaren klon bat izando da.</p></translation>
+ <translation><p>Mesedez hautatu makina birtual berriarentzako izen bat. Makina berria <b>%1</b> makinaren klon bat izango da.</p></translation>
</message>
<message>
<location line="+3"/>
@@ -8068,12 +6979,12 @@
<message>
<location line="+3"/>
<source><p>Please choose the type of clone you wish to create.</p><p>If you choose <b>Full clone</b>, an exact copy (including all virtual hard drive files) of the original virtual machine will be created.</p><p>If you choose <b>Linked clone</b>, a new machine will be created, but the virtual hard drive files will be tied to the virtual hard drive files of original machine and you will not be able to move the new virtual machi [...]
- <translation type="unfinished"></translation>
+ <translation><p>Mesedez hautatu sortzea nahi duzun klon mota.</p><p><b>Klon osoa</b> hautatzen baduzu, jatorrizko makina birtualaren kopia zehatz bat (diska gogor birtual agiri guztiak barne) sortuko da.</p><p><b>Loturiko klona</b> hautatzen baduzu, makina berri bat sortuko da, baina diska gogor birtual agiriak jatorrizko makinaren diska gogor birtual agirietara lotuko dira eta makina birtual berria ezingo duzu beste ordenagai [...]
</message>
<message>
<location line="+10"/>
<source><p>If you create a <b>Linked clone</b> then a new snapshot will be created in the original virtual machine as part of the cloning process.</p></source>
- <translation><p><b>Loturaturiko klona</b> sortzen baduzu argazki berri bat sortuko da jatorrizko makina birtualean klonazio aurrerabidearen atal bezala.</p></translation>
+ <translation><p><b>Loturiko klona</b> sortzen baduzu berehalako berri bat sortuko da jatorrizko makina birtualean klonatze aurrerabidearen atal bezala.</p></translation>
</message>
<message>
<location line="+4"/>
@@ -8094,22 +7005,22 @@
<message>
<location line="+3"/>
<source><p>Please choose which parts of the snapshot tree should be cloned with the machine.</p></source>
- <translation><p>Mesedez hautatu argazki zuhaitzaren zein atal klonatu behar diren makinarekin.</p></translation>
+ <translation><p>Mesedez hautatu berehalako zuhaitzaren zein atal klonatu behar diren makinarekin.</p></translation>
</message>
<message>
<location line="+2"/>
<source><p>If you choose <b>Current machine state</b>, the new machine will reflect the current state of the original machine and will have no snapshots.</p></source>
- <translation><p><b>Oraingo makina egoera</b> hautatzen baduzu, makina berriak jatorrizko makinaren uneko egoera isladatuko du eta ez du argazkirik izango.</p></translation>
+ <translation><p><b>Oraingo makina egoera</b> hautatzen baduzu, makina berriak jatorrizko makinaren uneko egoera isladatuko du eta ez du berehalakorik izango.</p></translation>
</message>
<message>
<location line="+3"/>
<source><p>If you choose <b>Current snapshot tree branch</b>, the new machine will reflect the current state of the original machine and will have matching snapshots for all snapshots in the tree branch starting at the current state in the original machine.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>Oraingo berehalako zuhaitzaren adarra</b> hautatzen baduzu, makina berriak jatorrizko makinaren uneko egoera isladatuko du eta zuhaitz adarreko berehalako guztiekin bat datozen berehalakoak izango ditu jatorrizko makinaren oraingo egoeratik hasita.</p></translation>
</message>
<message>
<location line="+5"/>
<source><p>If you choose <b>Everything</b>, the new machine will reflect the current state of the original machine and will have matching snapshots for all snapshots in the original machine.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>Guztia</b> hautatzen baduzu, makina berriak jatorrizko makinaren uneko egoera isladatuko du eta jatorrizko makinako berehalako guztiekin bat datozen berehalakoak izango ditu.</p></translation>
</message>
<message>
<location line="+16"/>
@@ -8121,7 +7032,7 @@
<location line="+1"/>
<location filename="../src/wizards/clonevm/UIWizardCloneVMPageExpert.cpp" line="+1"/>
<source>Current &snapshot tree branch</source>
- <translation>Oraingo &argazki zuhaitz adarra</translation>
+ <translation>Oraingo &berehalako zuhaitz adarra</translation>
</message>
<message>
<location line="+1"/>
@@ -8185,7 +7096,7 @@
<message>
<location line="+3"/>
<source><p>Please select the virtual machines that should be added to the appliance. You can select more than one. Please note that these machines have to be turned off before they can be exported.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Mesedez hautatu gailura gehitu behar diren makina birtualak. Bat baino gehiago hautatu ditzakezu. Mesedez ohartu makina hauek itzali egin behar direla esportatu ahal izan aurretik.</p></translation>
</message>
<message>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageBasic2.cpp" line="+115"/>
@@ -8196,7 +7107,7 @@
<message>
<location line="+3"/>
<source>Please choose where to create the virtual appliance. You can create it on your own computer, on the Sun Cloud service or on an S3 storage server.</source>
- <translation type="unfinished"></translation>
+ <translation>Mesedez hautatu non sortu gailu birtuala. Zeure ordenagailuan sortu dezakezu, Sun Cloud zerbitzuan edo S3 biltegiratze zerbitzari batean.</translation>
</message>
<message>
<location line="+3"/>
@@ -8212,7 +7123,7 @@
<location line="+1"/>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="+223"/>
<source>Sun &Cloud</source>
- <translation type="unfinished"></translation>
+ <translation>Sun &Cloud</translation>
</message>
<message>
<location line="+1"/>
@@ -8253,7 +7164,7 @@
<location line="+1"/>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="+1"/>
<source>&Bucket:</source>
- <translation type="unfinished"></translation>
+ <translation>&Ontzia:</translation>
</message>
<message>
<location line="+1"/>
@@ -8265,7 +7176,7 @@
<location line="+2"/>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="+2"/>
<source>Please choose a file to export the virtual appliance to</source>
- <translation type="unfinished"></translation>
+ <translation>Mesedez hautatu agiri bat gailu birtuala esportatzeko</translation>
</message>
<message>
<location line="+9"/>
@@ -8280,10 +7191,6 @@
<translation>OVF 2.0 heuskarri esperimental berrian idatzia.</translation>
</message>
<message>
- <source>Please choose a virtual appliance file</source>
- <translation type="obsolete">Mesedez hautatu makina birtual agiria</translation>
- </message>
- <message>
<location line="-9"/>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="-9"/>
<source>Open Virtualization Format Archive (%1)</source>
@@ -8326,10 +7233,6 @@
<translation>Idatzi ondorena OVF 0.9 heuskarria beste birtualizazio produktuekin bateragarria izateko.</translation>
</message>
<message>
- <source>&Write legacy OVF 0.9</source>
- <translation type="obsolete">&Idatzi ondorena OVF 0.9</translation>
- </message>
- <message>
<location line="+4"/>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="+4"/>
<source>Create a Manifest file for automatic data integrity checks on import.</source>
@@ -8344,7 +7247,7 @@
<message>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageBasic4.cpp" line="+3"/>
<source>This is the descriptive information which will be added to the virtual appliance. You can change it by double clicking on individual lines.</source>
- <translation type="unfinished"></translation>
+ <translation>Hauek gailu birtualera gehituko diren azalpen argibideak dira. Lerro bakoitzean klik-bikoitza eginez aldatu ditzakezu.</translation>
</message>
<message>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="-25"/>
@@ -8377,12 +7280,12 @@
<message>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageBasic3.cpp" line="-13"/>
<source>Choose a file to export the virtual appliance to...</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatu agiri bat gailu birtuala esportatzeko...</translation>
</message>
<message>
<location line="+73"/>
<source><p>Please choose a filename to export the OVF/OVA to.</p><p>If you use an <i>ova</i> extension, then all the files will be combined into one Open Virtualization Format Archive.</p><p>If you use an <i>ovf</i> extension, several files will be written separately.</p><p>Other extensions are not allowed.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Mesedez hautatu agirizen bat OVF/OVA bertara esportatzeko.</p><p><i>ova</i> hedapen bat erabiltzen baduzu agiri guztiak Birtualizazio Heuskarri Artxibo Irekia (OVFA) batean nahastuko dira.</p><p><i>ovf</i> hedapen bat erabiltzen baduzu agiri banandu ugari idatziko dira.</p><p>Beste hedapenak ez daude ahalbidetuta.</p></translation>
</message>
<message>
<location line="+11"/>
@@ -8400,7 +7303,7 @@
<message>
<location filename="../src/wizards/exportappliance/UIWizardExportAppPageExpert.cpp" line="+8"/>
<source>Choose a file to export the virtual appliance to...</source>
- <translation type="unfinished"></translation>
+ <translation>Hautatu agiri bat gailu birtuala esportatzeko...</translation>
</message>
</context>
<context>
@@ -8408,7 +7311,7 @@
<message>
<location filename="../src/wizards/firstrun/UIWizardFirstRun.cpp" line="+96"/>
<source>Select start-up disk</source>
- <translation>Hautatu Hasiera diska</translation>
+ <translation>Hautatu hasiera diska</translation>
</message>
<message>
<location line="+1"/>
@@ -8418,12 +7321,12 @@
<message>
<location filename="../src/wizards/firstrun/UIWizardFirstRunPageBasic.cpp" line="+108"/>
<source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from and should contain the operating system you wish to install on the virtual machine if you want to do that now. The disk will be ejected from the virtual drive automatically next time you switch the virtual machine off, but you can also do this yourself if needed u [...]
- <translation type="unfinished"></translation>
+ <translation><p>Mesedez hautatu zure makina birtual berria bertatik abiarazteko diska optiko birtual agiri bat edo diska duen gidagailu optiko fisiko bat.</p><p>Diska bertatik ordenagailu bat abiarazteko bezala egon behar da eta makina birtualean ezartzea nahi duzun sistema eragilea eduki behar du orain egitea nahi baduzu. Diska gidagailu birtualetik berezgaitasunez aterako da makina birtuala itzaltzen duzun hurrengoan, baina hau zeuk ere egin dezakezu beharrezk [...]
</message>
<message>
<location line="+10"/>
<source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from. As this virtual machine has no hard drive you will not be able to install an operating system on it at the moment.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Mesedez hautatu zure makina birtual berria bertatik abiarazteko diska optiko birtual agiri bat edo diska duen gidagailu optiko fisiko bat.</p><p>Diska bertatik ordenagailu bat abiarazteko bezala egon behar da. Makina birtual honek diska gogorrik ez duenez oraingoz ezingo duzu sistema eragile bat ezarri bertan.</p></translation>
</message>
<message>
<location line="+6"/>
@@ -8447,32 +7350,24 @@
<location filename="../src/wizards/importappliance/UIWizardImportAppPageBasic1.cpp" line="+61"/>
<location filename="../src/wizards/importappliance/UIWizardImportAppPageExpert.cpp" line="+96"/>
<source>Appliance to import</source>
- <translation>Inportatzeko makina birtuala</translation>
+ <translation>Inportatzeko gailua</translation>
</message>
<message>
<location line="+3"/>
<source><p>VirtualBox currently supports importing appliances saved in the Open Virtualization Format (OVF). To continue, select the file to import below.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>VirtualBox-ek Britualizazio Heuskarri Irekia (OVF) heuskarrian gordetako gailuak inportatzea sostengatzen du. Jarraitzeko, hautatu inportatzeko agiri bat azpian.</p></translation>
</message>
<message>
<location line="+3"/>
<location filename="../src/wizards/importappliance/UIWizardImportAppPageExpert.cpp" line="+1"/>
<source>Choose a virtual appliance file to import...</source>
- <translation type="unfinished"></translation>
+ <translation>Mesedez hautatu gailu birtual agiri bat inportatzeko...</translation>
</message>
<message>
<location line="+1"/>
<location filename="../src/wizards/importappliance/UIWizardImportAppPageExpert.cpp" line="+1"/>
<source>Please choose a virtual appliance file to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Open appliance...</source>
- <translation type="obsolete">Ireki makina birtuala...</translation>
- </message>
- <message>
- <source>Select an appliance to import</source>
- <translation type="obsolete">Hautatu inportatzeko makina birtuala</translation>
+ <translation>Mesedez hautatu gailu birtual agiri bat inportatzeko</translation>
</message>
<message>
<location line="+1"/>
@@ -8484,12 +7379,12 @@
<location filename="../src/wizards/importappliance/UIWizardImportAppPageBasic2.cpp" line="+56"/>
<location filename="../src/wizards/importappliance/UIWizardImportAppPageExpert.cpp" line="+1"/>
<source>Appliance settings</source>
- <translation>Makina birtual ezarpenak</translation>
+ <translation>Gailu ezarpenak</translation>
</message>
<message>
<location line="+3"/>
<source>These are the virtual machines contained in the appliance and the suggested settings of the imported VirtualBox machines. You can change many of the properties shown by double-clicking on the items and disable others using the check boxes below.</source>
- <translation type="unfinished"></translation>
+ <translation>Hauek dira gailuak dituen makina birtualak eta inportatutako VirtualBox makinen iradokitako ezarpenak. Erakusten diren ezaugarrietako asko aldatu ditzakezu klik-bikoitza eginez gaietan eta beste batzuk ezgaitu ditzakezu azpiko hauta kutxatilak erabiliz.</translation>
</message>
<message>
<location filename="../src/wizards/importappliance/UIWizardImportApp.cpp" line="-2"/>
@@ -8543,7 +7438,7 @@
<message>
<location line="+2"/>
<source><p>You can also choose to <b>split</b> the hard drive file into several files of up to two gigabytes each. This is mainly useful if you wish to store the virtual machine on removable USB devices or old systems, some of which cannot handle very large files.</source>
- <translation><p>Hautatu dezakezu ere diska gogorra agiri anitzetan <b>banantzea</b> bakoitza bi gigabyte arte. Hau erabilgarria da nagusiki makina birtuala USB gailu kengarri batean edo sistema zaharretan biltegiratzea nahi baduzu, hauetako batzuek ezin dute agiri oso handika kudeatu.</translation>
+ <translation><p>Hautatu dezakezu ere diska gogorra agiri anitzetan <b>banantzea</b> bakoitza bi gigabyte arte. Hau erabilgarria da nagusiki makina birtuala USB gailu kengarri batean edo sistema zaharretan biltegiratzea nahi baduzu, hauetako batzuek ezin dituzte agiri oso handiak kudeatu.</translation>
</message>
<message>
<location line="+4"/>
@@ -8700,10 +7595,6 @@
<context>
<name>VBoxEmptyFileSelector</name>
<message>
- <source>&Choose...</source>
- <translation type="obsolete">&Hautatu...</translation>
- </message>
- <message>
<location filename="../src/widgets/VBoxFilePathSelectorWidget.cpp" line="+725"/>
<source>Choose...</source>
<translation>Hautatu...</translation>
@@ -8717,13 +7608,9 @@
<translation><berrezarri berezkoetan></translation>
</message>
<message>
- <source>The actual default path value will be displayed after accepting the changes and opening this dialog again.</source>
- <translation type="obsolete">Oraingo berezko helburu balioa aldaketak onartu eta elkarrizketa hau berriro irekitakoan erakutsiko da.</translation>
- </message>
- <message>
<location line="+1"/>
<source>The actual default path value will be displayed after accepting the changes and opening this window again.</source>
- <translation type="unfinished"></translation>
+ <translation>Oraingo berezko helburu balioa aldaketak onartu eta elkarrizketa hau berriro irekitakoan erakutsiko da.</translation>
</message>
<message>
<location line="+5"/>
@@ -8756,19 +7643,11 @@
<translation>Leiho bat irekitzen du beste agiri bat hautatzeko.</translation>
</message>
<message>
- <source>Opens a dialog to select a different folder.</source>
- <translation type="obsolete">Beste agiritegi bat hautatzeko elkarrizketa bat irekitzen du.</translation>
- </message>
- <message>
<location line="-6"/>
<source>Resets the folder path to the default value.</source>
<translation>Agiritegi helburua berezko balioan berrezartzen du.</translation>
</message>
<message>
- <source>Opens a dialog to select a different file.</source>
- <translation type="obsolete">Beste agiri bat hautatzeko elkarrizketa bat irekitzen du.</translation>
- </message>
- <message>
<location line="+9"/>
<source>Resets the file path to the default value.</source>
<translation>Agiri helburua berezko balioan berrezartzen du.</translation>
@@ -8870,11 +7749,6 @@
<translation>ACPI</translation>
</message>
<message>
- <source>IO APIC</source>
- <comment>details report</comment>
- <translation type="obsolete">IO APIC</translation>
- </message>
- <message>
<location line="-43"/>
<source>Enabled</source>
<comment>details report (ACPI)</comment>
@@ -8887,16 +7761,6 @@
<translation>Ezgaituta</translation>
</message>
<message>
- <source>Enabled</source>
- <comment>details report (IO APIC)</comment>
- <translation type="obsolete">Gaituta</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>details report (IO APIC)</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
<location line="+209"/>
<source>Disabled</source>
<comment>details report (audio)</comment>
@@ -9003,7 +7867,7 @@
<location line="+25"/>
<source>Spawning</source>
<comment>SessionState</comment>
- <translation type="unfinished"></translation>
+ <translation>Errutean</translation>
</message>
<message>
<location line="+12"/>
@@ -9018,11 +7882,6 @@
<translation>Disketea</translation>
</message>
<message>
- <source>CD/DVD-ROM</source>
- <comment>DeviceType</comment>
- <translation type="obsolete">CD/DVD-ROM</translation>
- </message>
- <message>
<location line="+2"/>
<source>Hard Disk</source>
<comment>DeviceType</comment>
@@ -9128,7 +7987,7 @@
<location line="+1"/>
<source>Held</source>
<comment>USBDeviceState</comment>
- <translation type="unfinished"></translation>
+ <translation>Heutsia</translation>
</message>
<message>
<location line="+1"/>
@@ -9443,7 +8302,7 @@
<location line="+5"/>
<source><nobr>Serial No.: %1</nobr></source>
<comment>USB filter tooltip</comment>
- <translation><nobr>Serial Zbk.: %1</nobr></translation>
+ <translation><nobr>Serie Zbk.: %1</nobr></translation>
</message>
<message>
<location line="+5"/>
@@ -9637,7 +8496,7 @@
<location line="+62"/>
<source>Display</source>
<comment>details report</comment>
- <translation>Erakutsi</translation>
+ <translation>Erakuspena</translation>
</message>
<message>
<location filename="../src/converter/UIConverterBackendCOM.cpp" line="+51"/>
@@ -9693,25 +8552,25 @@
<location line="+7"/>
<source>Teleporting</source>
<comment>MachineState</comment>
- <translation type="unfinished"></translation>
+ <translation>Teleramatea</translation>
</message>
<message>
<location line="-6"/>
<source>Taking Live Snapshot</source>
<comment>MachineState</comment>
- <translation type="unfinished"></translation>
+ <translation>Zuzeneko Berehalakoa Hartzen</translation>
</message>
<message>
<location line="+5"/>
<source>Teleporting Paused VM</source>
<comment>MachineState</comment>
- <translation type="unfinished"></translation>
+ <translation>MB Teleramateak Pausatuta</translation>
</message>
<message>
<location line="+5"/>
<source>Restoring Snapshot</source>
<comment>MachineState</comment>
- <translation type="unfinished">Berehalakoa Leheneratzen</translation>
+ <translation>Berehalakoa Leheneratzen</translation>
</message>
<message>
<location line="-2"/>
@@ -9809,12 +8668,7 @@
<location line="+189"/>
<source>Some of the files in this hard disk chain are inaccessible. Please use the Virtual Media Manager in <b>Show Differencing Hard Disks</b> mode to inspect these files.</source>
<comment>medium</comment>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Failed to check media accessibility.</source>
- <comment>medium</comment>
- <translation type="obsolete">Hutsegitea multimedia sarbidea egiaztatzerakoan.</translation>
+ <translation>Diska gogor kate honetako zenbait agiri eskuraezinak dira. Mesedez erabii Medio Birtual Kudeatzailea <b>Erakutsi Diska Gogor Ezberdinduak</b> modua agiri hauek aztertzeko.</translation>
</message>
<message>
<location line="-191"/>
@@ -9822,25 +8676,16 @@
<translation>Hau makina ekinean dagoela ere aldatu dezakezu.</translation>
</message>
<message>
- <source><b>No media available</b></source>
- <comment>medium</comment>
- <translation type="obsolete"><b>Ez dago multimediarik eskuragarri</b></translation>
- </message>
- <message>
- <source>You can create media images using the virtual media manager.</source>
- <translation type="obsolete">Multimedia irudiak sortu ditzakezu multimedia birtual kudeatzailea erabiliz.</translation>
- </message>
- <message>
<location line="+12"/>
<source>Attaching this hard disk will be performed indirectly using a newly created differencing hard disk.</source>
<comment>medium</comment>
- <translation type="unfinished"></translation>
+ <translation>Diska gogor hau eransteak zeharka egingo da berriki sortutako ezberdinketa diska gogorra erabiliz.</translation>
</message>
<message>
<location line="+196"/>
<source>This base hard disk is indirectly attached using the following differencing hard disk:</source>
<comment>medium</comment>
- <translation type="unfinished"></translation>
+ <translation>Ohinarriko diska gogor hau zeharka erantsita dago hurrengo ezberdinketa diska gogorra erabiliz:</translation>
</message>
<message numerus="yes">
<location filename="../src/globals/VBoxGlobal.h" line="+168"/>
@@ -9977,16 +8822,6 @@
<translation>PB</translation>
</message>
<message>
- <source>Enabled</source>
- <comment>nested paging</comment>
- <translation type="obsolete">Gaituta</translation>
- </message>
- <message>
- <source>Disabled</source>
- <comment>nested paging</comment>
- <translation type="obsolete">Ezgaituta</translation>
- </message>
- <message>
<location filename="../src/runtime/UIIndicatorsPool.cpp" line="-7"/>
<source>Nested Paging</source>
<translation>Nested Orrialdeztapena</translation>
@@ -10030,7 +8865,7 @@
<location filename="../src/converter/UIConverterBackendCOM.cpp" line="-455"/>
<source>Fault Tolerant Syncing</source>
<comment>MachineState</comment>
- <translation type="unfinished"></translation>
+ <translation>Jasangarritasun Aldiberetze Hutsegitea</translation>
</message>
<message>
<location line="+20"/>
@@ -10306,7 +9141,7 @@
<location line="+163"/>
<source>Hold</source>
<comment>USBDeviceFilterAction</comment>
- <translation type="unfinished"></translation>
+ <translation>Heutsi</translation>
</message>
<message>
<location line="-62"/>
@@ -10402,7 +9237,7 @@
<location line="+27"/>
<source>Display</source>
<comment>DetailsElementType</comment>
- <translation>Erakutsi</translation>
+ <translation>Erakuspena</translation>
</message>
<message>
<location line="-26"/>
@@ -10531,7 +9366,7 @@
<message>
<location filename="../src/VBoxGlobalSettings.cpp" line="+268"/>
<source>The value '%1' of the key '%2' doesn't match the regexp constraint '%3'.</source>
- <translation type="unfinished"></translation>
+ <translation>'%2' giltzaren '%1' balioa ez dator bat '%3' regexp murrizketarekin.</translation>
</message>
<message>
<location line="-9"/>
@@ -10570,14 +9405,6 @@
<translation>&Ekintzak</translation>
</message>
<message>
- <source>&New...</source>
- <translation type="obsolete">&Berria...</translation>
- </message>
- <message>
- <source>&Add...</source>
- <translation type="obsolete">&Gehitu...</translation>
- </message>
- <message>
<location line="+4"/>
<source>R&emove</source>
<translation>&Kendu</translation>
@@ -10590,7 +9417,7 @@
<message>
<location line="+1"/>
<source>Re&fresh</source>
- <translation>&Berritu</translation>
+ <translation>B&erritu</translation>
</message>
<message>
<location line="+49"/>
@@ -10598,13 +9425,9 @@
<translation>Sarbidetasuna egiaztatzen</translation>
</message>
<message>
- <source>All files (*)</source>
- <translation type="obsolete">Agiri guztiak (*)</translation>
- </message>
- <message>
<location line="-543"/>
<source><i>Not Attached</i></source>
- <translation><i>Not Erantsita</i></translation>
+ <translation><i>Ez Erantsita</i></translation>
</message>
<message>
<location line="+1021"/>
@@ -10697,35 +9520,12 @@
<message>
<location line="-50"/>
<source>&Copy...</source>
- <translation>&Kopiatu...</translation>
+ <translation>K&opiatu...</translation>
</message>
<message>
<location line="+1"/>
<source>&Modify...</source>
- <translation>&Aldatu...</translation>
- </message>
- <message>
- <source>Create a new virtual hard drive</source>
- <translation type="obsolete">Sortu diska gogor birtual berri bat</translation>
- </message>
-</context>
-<context>
- <name>VBoxMiniToolBar</name>
- <message>
- <source>Always show the toolbar</source>
- <translation type="obsolete">Betik erakutsi tresnabarra</translation>
- </message>
- <message>
- <source>Exit Full Screen or Seamless Mode</source>
- <translation type="obsolete">Irten Ikusleiho Osotik edo Irudizko Modutik</translation>
- </message>
- <message>
- <source>Close VM</source>
- <translation type="obsolete">Itxi MB-a</translation>
- </message>
- <message>
- <source>Minimize Window</source>
- <translation type="obsolete">Txikiengotu Leihoa</translation>
+ <translation>A&ldatu...</translation>
</message>
</context>
<context>
@@ -10784,7 +9584,7 @@
<message>
<location filename="../src/selector/VBoxSnapshotsWgt.ui" line="+26"/>
<source>VBoxSnapshotsWgt</source>
- <translation>VBoxArgazkiWgta</translation>
+ <translation>VBoxBerehalakoWgta</translation>
</message>
<message>
<location filename="../src/selector/VBoxSnapshotsWgt.cpp" line="+158"/>
@@ -10862,7 +9662,7 @@
<message>
<location line="+8"/>
<source>Take a snapshot of the current virtual machine state</source>
- <translation>Hautu oraingo makina birtualaren egoera argazki bat</translation>
+ <translation>Hautu oraingo makina birtualaren egoera berehalako bat</translation>
</message>
<message>
<location line="-1"/>
@@ -10918,7 +9718,7 @@
<message>
<location filename="../src/VBoxTakeSnapshotDlg.ui" line="+26"/>
<source>Take Snapshot of Virtual Machine</source>
- <translation>Hartu Makina Birtualaren Argazki bat</translation>
+ <translation>Hartu Makina Birtualaren Berehalako bat</translation>
</message>
<message>
<location line="+38"/>
@@ -10928,14 +9728,14 @@
<message>
<location line="+20"/>
<source>Snapshot &Description</source>
- <translation>Argazki &Azalpena</translation>
+ <translation>Berehalakoaren &Azalpena</translation>
</message>
<message numerus="yes">
<location filename="../src/VBoxTakeSnapshotDlg.cpp" line="+73"/>
<source>Warning: You are taking a snapshot of a running machine which has %n immutable image(s) attached to it. As long as you are working from this snapshot the immutable image(s) will not be reset to avoid loss of data.</source>
- <translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <translation>
+ <numerusform>Kontuz: Ekinean dagoen makina baten berehalako bat hartzen ari zara berari %n irudi aldaezin erantsita dituela. Berehalako honetatik lanean ari zaren bitartean irudi aldaezinak ez dira berrezarriko datuak galtzea saihesteko.</numerusform>
+ <numerusform>Kontuz: Ekinean dagoen makina baten berehalako bat hartzen ari zara berari %n irudi aldaezin erantsita dituela. Berehalako honetatik lanean ari zaren bitartean irudi aldaezinak ez dira berrezarriko datuak galtzea saihesteko.</numerusform>
</translation>
</message>
</context>
@@ -10962,14 +9762,6 @@
<translation>%1 - Saio Argibideak</translation>
</message>
<message>
- <source>&Details</source>
- <translation type="obsolete">&Xehetasunak</translation>
- </message>
- <message>
- <source>&Runtime</source>
- <translation type="obsolete">&Runtime</translation>
- </message>
- <message>
<location line="+23"/>
<location line="+37"/>
<source>DMA Transfers</source>
diff --git a/src/VBox/Frontends/VirtualBox/src/main.cpp b/src/VBox/Frontends/VirtualBox/src/main.cpp
index e60abc0..1b029a9 100644
--- a/src/VBox/Frontends/VirtualBox/src/main.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/main.cpp
@@ -49,6 +49,7 @@
#endif
#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
#include <iprt/err.h>
#include <iprt/initterm.h>
#include <iprt/process.h>
@@ -645,26 +646,71 @@ int main(int argc, char **argv, char **envp)
#else /* VBOX_WITH_HARDENING */
+
+/**
+ * Special entrypoint used by the hardening code when something goes south.
+ *
+ * Display an error dialog to the user.
+ *
+ * @param pszWhere Indicates where the error occured.
+ * @param enmWhat Indicates what init operation was going on at the time.
+ * @param rc The VBox status code corresponding to the error.
+ * @param pszMsgFmt The message format string.
+ * @param va Format arguments.
+ */
extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
{
# ifdef RT_OS_DARWIN
ShutUpAppKit();
# endif /* RT_OS_DARWIN */
+ char szMsgBuf[_16K];
- /* We have to create QApplication anyway just to show the only one error-message.
- * This is a bit hackish as we don't have the argument vector handy. */
+ /*
+ * We have to create QApplication anyway just to show the only one error-message.
+ * This is a bit hackish as we don't have the argument vector handy.
+ */
int argc = 0;
char *argv[2] = { NULL, NULL };
QApplication a(argc, &argv[0]);
- /* Prepare the error-message: */
- QString strTitle = QApplication::tr("VirtualBox - Error In %1").arg(pszWhere);
-
- char szMsgBuf[1024];
+ /*
+ * The details starts off a properly formatted rc and where/what, we use
+ * the szMsgBuf for this, thus this have to come before the actual message
+ * formatting.
+ */
+ RTStrPrintf(szMsgBuf, sizeof(szMsgBuf),
+ "<!--EOM-->"
+ "where: %s\n"
+ "what: %d\n"
+ "%Rra\n",
+ pszWhere, enmWhat, rc);
+ QString strDetails = szMsgBuf;
+
+ /*
+ * Format the error message. Take whatever comes after a double new line as
+ * something better off in the details section.
+ */
RTStrPrintfV(szMsgBuf, sizeof(szMsgBuf), pszMsgFmt, va);
+
+ char *pszDetails = strstr(szMsgBuf, "\n\n");
+ if (pszDetails)
+ {
+ while (RT_C_IS_SPACE(*pszDetails))
+ *pszDetails++ = '\0';
+ if (*pszDetails)
+ {
+ strDetails += "\n";
+ strDetails += pszDetails;
+ }
+ RTStrStripR(szMsgBuf);
+ }
+
QString strText = QApplication::tr("<html><b>%1 (rc=%2)</b><br/><br/>").arg(szMsgBuf).arg(rc);
strText.replace(QString("\n"), QString("<br>"));
+ /*
+ * Append possibly helpful hints to the error message.
+ */
switch (enmWhat)
{
case kSupInitOp_Driver:
@@ -701,16 +747,28 @@ extern "C" DECLEXPORT(void) TrustedError(const char *pszWhere, SUPINITOP enmWhat
strText += "</html>";
+
# ifdef RT_OS_LINUX
- /* We have to to make sure that we display the error-message
- * after the parent displayed its own message. */
+ /*
+ * We have to to make sure that we display the error-message
+ * after the parent displayed its own message.
+ */
sleep(2);
-# endif /* RT_OS_LINUX */
+# endif
+
+ /*
+ * Create the message box and show it.
+ */
+ QString strTitle = QApplication::tr("VirtualBox - Error In %1").arg(pszWhere);
+ QIMessageBox msgBox(strTitle, strText, AlertIconType_Critical, AlertButton_Ok | AlertButtonOption_Default);
+ if (!strDetails.isEmpty())
+ msgBox.setDetailsText(strDetails);
+
+ msgBox.exec();
- QMessageBox::critical(0 /* parent */, strTitle, strText,
- QMessageBox::Abort /* 1st button */, 0 /* 2nd button */);
qFatal("%s", strText.toAscii().constData());
}
#endif /* VBOX_WITH_HARDENING */
+
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
index 9c33dc1..1a69209 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
@@ -1,12 +1,10 @@
/* $Id: UINetworkReply.cpp $ */
/** @file
- *
- * VBox frontends: Qt GUI ("VirtualBox"):
- * UINetworkReply stuff implementation
+ * VBox Qt GUI - UINetworkReply, i.e. HTTP/HTTPS for update pings++.
*/
/*
- * Copyright (C) 2012-2013 Oracle Corporation
+ * Copyright (C) 2012-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -22,156 +20,350 @@
#include <QFile>
#include <QThread>
#include <QRegExp>
+#include <QVector>
/* GUI includes: */
#include "UINetworkReply.h"
#include "UINetworkManager.h"
-#include "VBoxGlobal.h"
-#include "VBoxUtils.h"
+#ifndef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
+# include "VBoxGlobal.h"
+# include "VBoxUtils.h"
+#else
+# include <VBox/log.h>
+#endif
/* Other VBox includes; */
#include <iprt/initterm.h>
-#include <iprt/http.h>
+#include <iprt/crypto/pem.h>
+#include <iprt/crypto/store.h>
#include <iprt/err.h>
+#include <iprt/http.h>
+#include <iprt/path.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
#include <iprt/zip.h>
-/* Our network-reply thread: */
+/**
+ * Our network-reply thread
+ */
class UINetworkReplyPrivateThread : public QThread
{
+#ifndef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
Q_OBJECT;
+#endif
public:
/* Constructor: */
UINetworkReplyPrivateThread(const QNetworkRequest &request);
- /* API: Read stuff: */
- const QByteArray& readAll() const { return m_reply; }
+ /** Returns short descriptive context of thread's current operation. */
+ const QString context() const { return m_strContext; }
- /* API: Error stuff: */
+ /** @name APIs
+ * @{ */
+ /** Read everything. */
+ const QByteArray& readAll() const { return m_reply; }
+ /** IRPT error status. */
int error() const { return m_iError; }
-
- /* API: HTTP stuff: */
+ /** Abort HTTP request. */
void abort();
+ /** @} */
private:
-
- /* Helpers: HTTP stuff: */
+ /** @name Helpers - HTTP stuff
+ * @{ */
int applyProxyRules();
int applyHttpsCertificates();
int applyRawHeaders();
int performMainRequest();
+ /** @} */
/* Helper: Main thread runner: */
void run();
- /* Static helper: File stuff: */
+ /** Additinoal download nfo about wanted certificate. */
+ typedef struct CERTINFO
+ {
+ /** Filename in the zip file we download (PEM). */
+ const char *pszZipFile;
+ /** List of direct URLs to PEM formatted files.. */
+ const char *apszUrls[4];
+ } CERTINFO;
+
+ /** @name Static helpers for HTTP and Certificates handling.
+ * @{ */
static QString fullCertificateFileName();
-
- /* Static helpers: HTTP stuff: */
- static int abort(RTHTTP pHttp);
- static int applyProxyRules(RTHTTP pHttp, const QString &strHostName, int iPort);
- static int applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName);
- static int applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
- static int performGetRequestForText(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply);
- static int performGetRequestForBinary(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply);
- static int checkCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName);
- static int decompressCertificate(const QByteArray &package, QByteArray &certificate, const QString &strName);
- static int downloadCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName);
- static int downloadCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate);
- static int downloadCertificatePca3(RTHTTP pHttp, QByteArray &certificate);
- static int verifyCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate);
- static int verifyCertificatePca3(RTHTTP pHttp, QByteArray &certificate);
- static int verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512);
- static int saveCertificates(const QString &strFullCertificateFileName, const QByteArray &certificatePca3G5, const QByteArray &certificatePca3);
- static int saveCertificate(QFile &file, const QByteArray &certificate);
+ static int applyProxyRules(RTHTTP hHttp, const QString &strHostName, int iPort);
+ static int applyRawHeaders(RTHTTP hHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
+ static unsigned countCertsFound(bool const *pafFoundCerts);
+ static bool areAllCertsFound(bool const *pafFoundCerts);
+ static int refreshCertificates(RTHTTP hHttp, PRTCRSTORE phStore, bool *pafFoundCerts, const char *pszCaCertFile);
+ static void downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
+ PRTERRINFOSTATIC pStaticErrInfo);
+ static int convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore, void const *pvResponse,
+ size_t cbResponse, PCRTCRCERTWANTED pWantedCert);
+ /** @} */
+
+ /** Holds short descriptive context of thread's current operation. */
+ QString m_strContext;
/* Variables: */
QNetworkRequest m_request;
int m_iError;
- RTHTTP m_pHttp;
+ /** IPRT HTTP client instance handle. */
+ RTHTTP m_hHttp;
QByteArray m_reply;
- static const QString m_strCertificateFileName;
+
+ static const char * const s_apszRootsZipUrls[];
+ static const CERTINFO s_CertInfoPcaCls3Gen5;
+ static const RTCRCERTWANTED s_aCerts[];
+ static const QString s_strCertificateFileName;
+
+#ifdef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
+public:
+ static void testIt(RTTEST hTest);
+#endif
};
-/* static */
-const QString UINetworkReplyPrivateThread::m_strCertificateFileName = QString("vbox-ssl-cacertificate.crt");
+
+/**
+ * URLs to root zip files containing certificates we want.
+ */
+/*static*/ const char * const UINetworkReplyPrivateThread::s_apszRootsZipUrls[] =
+{
+ "http://www.symantec.com/content/en/us/enterprise/verisign/roots/roots.zip"
+};
+
+
+/**
+ * Download details for
+ */
+/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5 =
+{
+ /*.pszZipFile =*/
+ "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
+ /*.apszUrls[] =*/
+ {
+ "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
+ "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
+ "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
+ NULL,
+ }
+};
+
+
+/**
+ * Details on the certificates we are after.
+ * The pvUser member points to a UINetworkReplyPrivateThread::CERTINFO.
+ */
+/* static */ const RTCRCERTWANTED UINetworkReplyPrivateThread::s_aCerts[] =
+{
+ /*[0] =*/
+ {
+ /*.pszSubject =*/
+ "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, "
+ "CN=VeriSign Class 3 Public Primary Certification Authority - G5",
+ /*.cbEncoded =*/ 0x4d7,
+ /*.Sha1Fingerprint =*/ true,
+ /*.Sha512Fingerprint =*/ true,
+ /*.abSha1 =*/
+ {
+ 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
+ 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
+ },
+ /*.abSha512 =*/
+ {
+ 0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
+ 0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
+ 0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
+ 0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
+ 0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
+ 0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
+ 0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
+ 0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
+ },
+ /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5
+ },
+};
+
+
+/** The certificate file name (no path). */
+/* static */ const QString UINetworkReplyPrivateThread::s_strCertificateFileName = QString("vbox-ssl-cacertificate.crt");
+
UINetworkReplyPrivateThread::UINetworkReplyPrivateThread(const QNetworkRequest &request)
: m_request(request)
, m_iError(VINF_SUCCESS)
- , m_pHttp(0)
+ , m_hHttp(NIL_RTHTTP)
{
}
void UINetworkReplyPrivateThread::abort()
{
/* Call for abort: */
- abort(m_pHttp);
+ if (m_hHttp != NIL_RTHTTP)
+ RTHttpAbort(m_hHttp);
}
int UINetworkReplyPrivateThread::applyProxyRules()
{
- /* Make sure proxy is enabled in Proxy Manager: */
+ /* Set thread context: */
+ m_strContext = tr("During proxy configuration");
+
+#ifndef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
+ /* Get the proxymanager: */
UIProxyManager proxyManager(vboxGlobal().settings().proxySettings());
- if (!proxyManager.proxyEnabled())
- return VINF_SUCCESS;
- /* Apply proxy rules: */
- return applyProxyRules(m_pHttp,
- proxyManager.proxyHost(),
- proxyManager.proxyPort().toUInt());
+ /* If the specific proxy settings aren't enabled, we'll use the
+ system default proxy. Otherwise assume it's configured. */
+ if (proxyManager.proxyEnabled())
+ return RTHttpSetProxy(m_hHttp,
+ proxyManager.proxyHost().toUtf8().constData(),
+ proxyManager.proxyPort().toUInt(),
+ NULL /* pszProxyUser */, NULL /* pszProxyPwd */);
+
+ /** @todo This should be some kind of tristate:
+ * - system configured proxy ("proxyDisabled" as well as default "")
+ * - user configured proxy ("proxyEnabled").
+ * - user configured "no proxy" (currently missing).
+ * In the two last cases, call RTHttpSetProxy.
+ *
+ * Alternatively, we could opt not to give the user a way of doing "no proxy",
+ * that would require no real changes to the visible GUI... Just a thought.
+ */
+#endif
+ return RTHttpUseSystemProxySettings(m_hHttp);
}
int UINetworkReplyPrivateThread::applyHttpsCertificates()
{
- /* Prepare variables: */
- const QString strFullCertificateFileName(fullCertificateFileName());
- int rc = VINF_SUCCESS;
-
- /* Check certificates if present: */
- if (QFile::exists(strFullCertificateFileName))
- rc = checkCertificates(m_pHttp, strFullCertificateFileName);
- else
- rc = VERR_FILE_NOT_FOUND;
-
- /* Download certificates if necessary: */
- if (!RT_SUCCESS(rc))
- rc = downloadCertificates(m_pHttp, strFullCertificateFileName);
+ /* Set thread context: */
+ m_strContext = tr("During certificate downloading");
- /* Apply certificates: */
+ /*
+ * Calc the filename of the CA certificate file.
+ */
+ const QString strFullCertificateFileName(fullCertificateFileName());
+ QByteArray utf8FullCertificateFileName = strFullCertificateFileName.toUtf8();
+ const char *pszCaCertFile = utf8FullCertificateFileName.constData();
+
+ /*
+ * Check the state of our CA certificate file, it's one of the following:
+ * - Missing, recreate from scratch (= refresh).
+ * - Everything is there and it is less than 28 days old, do nothing.
+ * - Everything is there but it's older than 28 days, refresh.
+ * - Missing certificates and is older than 1 min, refresh.
+ *
+ * Start by creating a store for loading the current state into, as we'll
+ * be need that for the refresh.
+ */
+ RTCRSTORE hCurStore = NIL_RTCRSTORE;
+ int rc = RTCrStoreCreateInMem(&hCurStore, 256);
if (RT_SUCCESS(rc))
- rc = applyCertificates(m_pHttp, strFullCertificateFileName);
+ {
+ bool fRefresh = true;
+ bool afCertsFound[RT_ELEMENTS(s_aCerts)];
+ RT_ZERO(afCertsFound);
+
+ /*
+ * Load the file if it exists.
+ *
+ * To effect regular updates, we need the modification date of the file,
+ * so we use RTPathQueryInfoEx here and not RTFileExists.
+ */
+ RTFSOBJINFO Info;
+ int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if ( RT_SUCCESS(rc)
+ && RTFS_IS_FILE(Info.Attr.fMode))
+ {
+ RTERRINFOSTATIC StaticErrInfo;
+ rc = RTCrStoreCertAddFromFile(hCurStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
+ RTErrInfoInitStatic(&StaticErrInfo));
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
+ else
+ AssertRC(rc);
+
+ /*
+ * Scan the store the for certificates we need, then see what we
+ * need to do wrt file age.
+ */
+ rc = RTCrStoreCertCheckWanted(hCurStore, s_aCerts, RT_ELEMENTS(s_aCerts), afCertsFound);
+ AssertRC(rc);
+ RTTIMESPEC RefreshAge;
+ uint32_t cSecRefresh = rc == VINF_SUCCESS ? 28 * RT_SEC_1DAY /* all found */ : 60 /* stuff missing */;
+ fRefresh = RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&RefreshAge), cSecRefresh)) <= 0;
+ }
- /* Return result-code: */
+ /*
+ * Refresh the file if necessary.
+ */
+ if (fRefresh)
+ refreshCertificates(m_hHttp, &hCurStore, afCertsFound, pszCaCertFile);
+
+ RTCrStoreRelease(hCurStore);
+
+ /*
+ * Final verdict.
+ */
+ if (areAllCertsFound(afCertsFound))
+ rc = VINF_SUCCESS;
+ else
+ rc = VERR_NOT_FOUND; /** @todo r=bird: Why not try and let RTHttpGet* bitch if the necessary certs are missing? */
+
+ /*
+ * Set our custom CA file.
+ */
+ if (RT_SUCCESS(rc))
+ rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
+ }
return rc;
}
int UINetworkReplyPrivateThread::applyRawHeaders()
{
+ /* Set thread context: */
+ m_strContext = tr("During network request");
+
/* Make sure we have a raw headers at all: */
QList<QByteArray> headers = m_request.rawHeaderList();
if (headers.isEmpty())
return VINF_SUCCESS;
/* Apply raw headers: */
- return applyRawHeaders(m_pHttp, headers, m_request);
+ return applyRawHeaders(m_hHttp, headers, m_request);
}
int UINetworkReplyPrivateThread::performMainRequest()
{
- /* Perform GET request: */
- return performGetRequestForText(m_pHttp, m_request, m_reply);
+ /* Set thread context: */
+ m_strContext = tr("During network request");
+
+ /* Paranoia: */
+ m_reply.clear();
+
+ /* Perform blocking HTTP GET request: */
+ char *pszResponse;
+ /** @todo r=bird: Use RTHttpGetBinary? */
+ int rc = RTHttpGetText(m_hHttp, m_request.url().toString().toUtf8().constData(), &pszResponse);
+ if (RT_SUCCESS(rc))
+ {
+ m_reply = QByteArray(pszResponse);
+ RTHttpFreeResponseText(pszResponse);
+ }
+
+ return rc;
}
void UINetworkReplyPrivateThread::run()
{
/* Init: */
- RTR3InitExeNoArguments(RTR3INIT_FLAGS_SUPLIB);
+ RTR3InitExeNoArguments(RTR3INIT_FLAGS_SUPLIB); /** @todo r=bird: WTF? */
/* Create HTTP object: */
if (RT_SUCCESS(m_iError))
- m_iError = RTHttpCreate(&m_pHttp);
+ m_iError = RTHttpCreate(&m_hHttp);
/* Apply proxy-rules: */
if (RT_SUCCESS(m_iError))
@@ -189,63 +381,33 @@ void UINetworkReplyPrivateThread::run()
if (RT_SUCCESS(m_iError))
m_iError = performMainRequest();
- /* Destroy HTTP object: */
- if (m_pHttp)
+ /* Destroy HTTP client instance: */
+ RTHTTP hHttp = m_hHttp;
+ if (hHttp != NIL_RTHTTP)
{
- RTHttpDestroy(m_pHttp);
- m_pHttp = 0;
+ /** @todo r=bird: There is a race here between this and abort()! */
+ m_hHttp = NIL_RTHTTP;
+ RTHttpDestroy(hHttp);
}
}
/* static */
QString UINetworkReplyPrivateThread::fullCertificateFileName()
{
+#ifndef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
const QDir homeDir(QDir::toNativeSeparators(vboxGlobal().homeFolder()));
- return QDir::toNativeSeparators(homeDir.absoluteFilePath(m_strCertificateFileName));
-}
-
-/* static */
-int UINetworkReplyPrivateThread::abort(RTHTTP pHttp)
-{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Call for HTTP abort: */
- return RTHttpAbort(pHttp);
-}
-
-/* static */
-int UINetworkReplyPrivateThread::applyProxyRules(RTHTTP pHttp, const QString &strHostName, int iPort)
-{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Apply HTTP proxy: */
- return RTHttpSetProxy(pHttp,
- strHostName.toAscii().constData(),
- iPort,
- 0 /* login */, 0 /* password */);
-}
-
-/* static */
-int UINetworkReplyPrivateThread::applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
-{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Apply HTTPs certificates: */
- return RTHttpSetCAFile(pHttp, strFullCertificateFileName.toUtf8().constData());
+ return QDir::toNativeSeparators(homeDir.absoluteFilePath(s_strCertificateFileName));
+#else
+ return QString("/not/such/agency/non-existing-file.cer");
+#endif
}
/* static */
-int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request)
+int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP hHttp, const QList<QByteArray> &headers, const QNetworkRequest &request)
{
/* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
+ if (hHttp == NIL_RTHTTP)
+ return VERR_INVALID_HANDLE;
/* We should format them first: */
QVector<QByteArray> formattedHeaders;
@@ -260,335 +422,302 @@ int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP pHttp, const QList<QByte
const char **ppFormattedHeaders = formattedHeaderPointers.data();
/* Apply HTTP headers: */
- return RTHttpSetHeaders(pHttp, formattedHeaderPointers.size(), ppFormattedHeaders);
+ return RTHttpSetHeaders(hHttp, formattedHeaderPointers.size(), ppFormattedHeaders);
}
-/* static */
-int UINetworkReplyPrivateThread::performGetRequestForText(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply)
+/**
+ * Counts the number of certificates found in a search result array.
+ *
+ * @returns Number of wanted certifcates we've found.
+ * @param pafFoundCerts Array parallel to s_aCerts with the status of
+ * each wanted certificate.
+ */
+/*static*/ unsigned
+UINetworkReplyPrivateThread::countCertsFound(bool const *pafFoundCerts)
{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Perform blocking HTTP GET request: */
- char *pszBuffer = 0;
- int rc = RTHttpGetText(pHttp,
- request.url().toString().toAscii().constData(),
- &pszBuffer);
- reply = QByteArray(pszBuffer);
- RTMemFree(pszBuffer);
- return rc;
+ unsigned cFound = 0;
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ cFound += pafFoundCerts[i];
+ return cFound;
}
-/* static */
-int UINetworkReplyPrivateThread::performGetRequestForBinary(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply)
+/**
+ * Checks if we've found all the necessary certificates or not.
+ *
+ * @returns true if we have, false if we haven't.
+ * @param pafFoundCerts Array parallel to s_aCerts with the status of
+ * each wanted certificate.
+ */
+/*static*/ bool
+UINetworkReplyPrivateThread::areAllCertsFound(bool const *pafFoundCerts)
{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Perform blocking HTTP GET request: */
- void *pBuffer = 0;
- size_t size = 0;
- int rc = RTHttpGetBinary(pHttp,
- request.url().toString().toAscii().constData(),
- &pBuffer, &size);
- reply = QByteArray((const char*)pBuffer, (int)size);
- RTMemFree(pBuffer);
- return rc;
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ if (!pafFoundCerts[i])
+ return false;
+ return true;
}
-/* static */
-int UINetworkReplyPrivateThread::checkCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
-{
- /* Open certificates file: */
- QFile file(strFullCertificateFileName);
- bool fFileOpened = file.open(QIODevice::ReadOnly);
- int rc = fFileOpened ? VINF_SUCCESS : VERR_OPEN_FAILED;
-
- /* Read certificates file: */
+/**
+ * Refresh the certificates.
+ *
+ * @return IPRT status code for the testcase.
+ * @param hHttp The HTTP client instance. (Can be NIL when
+ * running the testcase.)
+ * @param phStore On input, this holds the current store, so that
+ * we can fish out wanted certificates from it.
+ * On successful return, this is replaced with a
+ * new store reflecting the refrehsed content of
+ * @a pszCaCertFile.
+ * @param pafFoundCerts On input, this holds the certificates found in
+ * the current store. On return, this reflects
+ * what is current in the @a pszCaCertFile. The
+ * array runs parallel to s_aCerts.
+ * @param pszCaCertFile Where to write the refreshed certificates if
+ * we've managed to gather a collection that is at
+ * least as good as the old one.
+ */
+/*static*/ int
+UINetworkReplyPrivateThread::refreshCertificates(RTHTTP hHttp, PRTCRSTORE phStore, bool *pafFoundCerts,
+ const char *pszCaCertFile)
+{
+ /*
+ * Collect the standard assortment of SSL certificates.
+ */
+ uint32_t cHint = RTCrStoreCertCount(*phStore);
+ RTCRSTORE hNewStore;
+ int rc = RTCrStoreCreateInMem(&hNewStore, cHint > 32 && cHint < _32K ? cHint + 16 : 256);
if (RT_SUCCESS(rc))
{
- /* Parse the file content: */
- QString strData(file.readAll());
-#define CERT "-{5}BEGIN CERTIFICATE-{5}[\\s\\S\\r{0,1}\\n]+-{5}END CERTIFICATE-{5}"
-#define REOLD "(" CERT ")\\r{0,1}\\n(" CERT ")\\r{0,1}\\n(" CERT ")"
-#define RENEW "(" CERT ")\\r{0,1}\\n(" CERT ")"
- /* First check if we have the old format with three certificates: */
- QRegExp regExp(REOLD);
- regExp.setMinimal(true);
-
- /* If so, fake an error to force re-downloading */
- if (regExp.indexIn(strData) != -1)
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
-
- /* Otherwise, check for two certificates: */
- if (RT_SUCCESS(rc))
- {
- regExp.setPattern(RENEW);
- regExp.setMinimal(true);
- if (regExp.indexIn(strData) == -1)
- rc = VERR_FILE_IO_ERROR;
- }
-
- /* Verify certificates: */
- if (RT_SUCCESS(rc))
- {
- QByteArray certificate = regExp.cap(1).toAscii();
- rc = verifyCertificatePca3G5(pHttp, certificate);
- }
- if (RT_SUCCESS(rc))
+ RTERRINFOSTATIC StaticErrInfo;
+ rc = RTHttpGatherCaCertsInStore(hNewStore, 0 /*fFlags*/, RTErrInfoInitStatic(&StaticErrInfo));
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ LogRel(("refreshCertificates/#1: %s\n", StaticErrInfo.Core.pszMsg));
+ else if (rc == VERR_NOT_FOUND)
+ LogRel(("refreshCertificates/#1: No trusted SSL certs found on the system, will try download...\n"));
+ else
+ AssertLogRelRC(rc);
+ if (RT_SUCCESS(rc) || rc == VERR_NOT_FOUND)
{
- QByteArray certificate = regExp.cap(2).toAscii();
- rc = verifyCertificatePca3(pHttp, certificate);
+ /*
+ * Check and see what we've got. If we haven't got all we desire,
+ * try add it from the previous store.
+ */
+ bool afNewFoundCerts[RT_ELEMENTS(s_aCerts)];
+ RT_ZERO(afNewFoundCerts); /* paranoia */
+
+ rc = RTCrStoreCertCheckWanted(hNewStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
+ AssertLogRelRC(rc);
+ Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts));
+ if (rc != VINF_SUCCESS)
+ {
+ rc = RTCrStoreCertAddWantedFromStore(hNewStore,
+ RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ *phStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
+ AssertLogRelRC(rc);
+ Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts));
+ }
+
+ /*
+ * If that didn't help, seek out certificates in more obscure places,
+ * like java, mozilla and mutt.
+ */
+ if (rc != VINF_SUCCESS)
+ {
+ rc = RTCrStoreCertAddWantedFromFishingExpedition(hNewStore,
+ RTCRCERTCTX_F_ADD_IF_NOT_FOUND
+ | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts,
+ RTErrInfoInitStatic(&StaticErrInfo));
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ LogRel(("refreshCertificates/#2: %s\n", StaticErrInfo.Core.pszMsg));
+ Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts));
+ }
+
+ /*
+ * If that didn't help, try download the certificates.
+ */
+ if (rc != VINF_SUCCESS && hHttp != NIL_RTHTTP)
+ downloadMissingCertificates(hNewStore, afNewFoundCerts, hHttp, &StaticErrInfo);
+
+ /*
+ * If we've got the same or better hit rate than the old store,
+ * replace the CA certs file.
+ */
+ if ( areAllCertsFound(afNewFoundCerts)
+ || countCertsFound(afNewFoundCerts) >= countCertsFound(pafFoundCerts) )
+ {
+ rc = RTCrStoreCertExportAsPem(hNewStore, 0 /*fFlags*/, pszCaCertFile);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel(("refreshCertificates/#3: Found %u/%u SSL certs we/you trust (previously %u/%u).\n",
+ countCertsFound(afNewFoundCerts), RTCrStoreCertCount(hNewStore),
+ countCertsFound(pafFoundCerts), RTCrStoreCertCount(*phStore) ));
+
+ memcpy(pafFoundCerts, afNewFoundCerts, sizeof(afNewFoundCerts));
+ RTCrStoreRelease(*phStore);
+ *phStore = hNewStore;
+ hNewStore = NIL_RTCRSTORE;
+ }
+ else
+ {
+ RT_ZERO(pafFoundCerts);
+ LogRel(("refreshCertificates/#3: RTCrStoreCertExportAsPem unexpectedly failed with %Rrc\n", rc));
+ }
+ }
+ else
+ LogRel(("refreshCertificates/#3: Sticking with the old file, missing essential certs.\n"));
}
-#undef CERT
-#undef REOLD
-#undef RENEW
+ RTCrStoreRelease(hNewStore);
}
-
- /* Close certificates file: */
- if (fFileOpened)
- file.close();
-
- /* Return result-code: */
return rc;
}
-/* static */
-int UINetworkReplyPrivateThread::decompressCertificate(const QByteArray &package, QByteArray &certificate, const QString &strName)
+/*static*/ void
+UINetworkReplyPrivateThread::downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
+ PRTERRINFOSTATIC pStaticErrInfo)
{
- /* Decompress certificate: */
- void *pDecompressedBuffer;
- size_t cDecompressedSize;
- int rc = RTZipPkzipMemDecompress(&pDecompressedBuffer, &cDecompressedSize, package, package.size(), strName.toLatin1().constData());
- if (RT_SUCCESS(rc))
- {
- /* Copy certificate: */
- certificate = QByteArray((const char*)pDecompressedBuffer, (int)cDecompressedSize);
- /* Free decompressed buffer: */
- RTMemFree(pDecompressedBuffer);
- }
- /* Return result: */
- return rc;
-}
-
-/* static */
-int UINetworkReplyPrivateThread::downloadCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName)
-{
- /* Prepare certificates: */
- QByteArray certificatePca3G5;
- QByteArray certificatePca3;
-
- /* Receive certificate package: */
- QByteArray package;
- const QNetworkRequest address(QUrl("http://www.verisign.com/support/roots.zip"));
- int rc = performGetRequestForBinary(pHttp, address, package);
- /* UnZIP PCA-3G5 certificate: */
- if (RT_SUCCESS(rc))
- {
- rc = decompressCertificate(package, certificatePca3G5,
- "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem");
- /* Verify PCA-3G5 certificate: */
- if (RT_SUCCESS(rc))
- rc = verifyCertificatePca3G5(pHttp, certificatePca3G5);
- }
- /* UnZIP PCA-3 certificate: */
- if (RT_SUCCESS(rc))
- {
- rc = decompressCertificate(package, certificatePca3,
- "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem");
- /* Verify PCA-3 certificate: */
- if (RT_SUCCESS(rc))
- rc = verifyCertificatePca3(pHttp, certificatePca3);
- }
+ int rc;
- /* Fallback.. download certificates separately: */
- if (!RT_SUCCESS(rc))
+ /*
+ * Try get the roots.zip from symantec (or virtualbox.org) first.
+ */
+ for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(s_apszRootsZipUrls); iUrl++)
{
- /* Reset result: */
- rc = VINF_SUCCESS;
- /* Download PCA-3G5 certificate: */
- if (RT_SUCCESS(rc))
- rc = downloadCertificatePca3G5(pHttp, certificatePca3G5);
- /* Download PCA-3 certificate: */
+ void *pvRootsZip;
+ size_t cbRootsZip;
+ rc = RTHttpGetBinary(hHttp, s_apszRootsZipUrls[iUrl], &pvRootsZip, &cbRootsZip);
if (RT_SUCCESS(rc))
- rc = downloadCertificatePca3(pHttp, certificatePca3);
+ {
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ if (!pafNewFoundCerts[i])
+ {
+ CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
+ if (pInfo->pszZipFile)
+ {
+ void *pvFile;
+ size_t cbFile;
+ rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, pInfo->pszZipFile);
+ if (RT_SUCCESS(rc))
+ {
+ rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvFile, cbFile, &s_aCerts[i]);
+ RTMemFree(pvFile);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Successfully added. Mark it as found and return if we've got them all.
+ */
+ pafNewFoundCerts[i] = true;
+ if (areAllCertsFound(pafNewFoundCerts))
+ {
+ RTHttpFreeResponse(pvRootsZip);
+ return;
+ }
+ }
+ }
+ }
+ }
+ RTHttpFreeResponse(pvRootsZip);
+ }
}
- /* Save certificates: */
- if (RT_SUCCESS(rc))
- saveCertificates(strFullCertificateFileName, certificatePca3G5, certificatePca3);
-
- /* Return result-code: */
- return rc;
-}
-
-/* static */
-int UINetworkReplyPrivateThread::downloadCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate)
-{
- /* Receive certificate: */
- const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem"));
- int rc = performGetRequestForText(pHttp, address, certificate);
-
- /* Verify certificate: */
- if (RT_SUCCESS(rc))
- rc = verifyCertificatePca3G5(pHttp, certificate);
-
- /* Return result-code: */
- return rc;
+ /*
+ * Try download certificates separately.
+ */
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ if (!pafNewFoundCerts[i])
+ {
+ CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
+ for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(pInfo->apszUrls); i++)
+ if (pInfo->apszUrls[iUrl])
+ {
+ void *pvResponse;
+ size_t cbResponse;
+ rc = RTHttpGetBinary(hHttp, pInfo->apszUrls[iUrl], &pvResponse, &cbResponse);
+ if (RT_SUCCESS(rc))
+ {
+ rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvResponse, cbResponse, &s_aCerts[i]);
+ RTHttpFreeResponse(pvResponse);
+ if (RT_SUCCESS(rc))
+ {
+ pafNewFoundCerts[i] = true;
+ break;
+ }
+ }
+ }
+ }
}
-/* static */
-int UINetworkReplyPrivateThread::downloadCertificatePca3(RTHTTP pHttp, QByteArray &certificate)
-{
- /* Receive certificate: */
- const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem"));
- int rc = performGetRequestForText(pHttp, address, certificate);
-
- /* Verify certificate: */
+/**
+ * Converts a PEM certificate, verifies it against @a pCertInfo and adds it to
+ * the given store.
+ *
+ * @returns IPRT status code.
+ * @param hStore The store to add it to.
+ * @param pvResponse The raw PEM certificate file bytes.
+ * @param cbResponse The number of bytes.
+ * @param pWantedCert The certificate info (we use hashes and encoded
+ * size).
+ */
+/*static*/ int
+UINetworkReplyPrivateThread::convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore,
+ void const *pvResponse, size_t cbResponse,
+ PCRTCRCERTWANTED pWantedCert)
+{
+ /*
+ * Convert the PEM certificate to its binary form so we can hash it.
+ */
+ static RTCRPEMMARKERWORD const s_aWords_Certificate[] = { { RT_STR_TUPLE("CERTIFICATE") } };
+ static RTCRPEMMARKER const s_aCertificateMarkers[] = { { s_aWords_Certificate, RT_ELEMENTS(s_aWords_Certificate) }, };
+ RTERRINFOSTATIC StaticErrInfo;
+ PCRTCRPEMSECTION pSectionHead;
+ int rc = RTCrPemParseContent(pvResponse, cbResponse, 0 /*fFlags*/,
+ &s_aCertificateMarkers[0], RT_ELEMENTS(s_aCertificateMarkers),
+ &pSectionHead, RTErrInfoInitStatic(&StaticErrInfo));
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ LogRel(("RTCrPemParseContent: %s\n", StaticErrInfo.Core.pszMsg));
if (RT_SUCCESS(rc))
- rc = verifyCertificatePca3(pHttp, certificate);
-
- /* Return result-code: */
- return rc;
-}
-
-/* static */
-int UINetworkReplyPrivateThread::verifyCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate)
-{
- /* PCA 3G5 secure hash algorithm 1: */
- const unsigned char baSha1PCA3G5[] =
- {
- 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
- 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
- };
- /* PCA 3G5 secure hash algorithm 512: */
- const unsigned char baSha512PCA3G5[] =
{
- 0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
- 0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c,
- 0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf,
- 0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3,
- 0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46,
- 0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3,
- 0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb,
- 0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
- };
- QByteArray pca3G5sha1 = QByteArray::fromRawData((const char *)baSha1PCA3G5, sizeof(baSha1PCA3G5));
- QByteArray pca3G5sha512 = QByteArray::fromRawData((const char *)baSha512PCA3G5, sizeof(baSha512PCA3G5));
-
- /* Verify certificate: */
- return verifyCertificate(pHttp, certificate, pca3G5sha1, pca3G5sha512);
-}
-
-/* static */
-int UINetworkReplyPrivateThread::verifyCertificatePca3(RTHTTP pHttp, QByteArray &certificate)
-{
- /* PCA 3 secure hash algorithm 1: */
- const unsigned char baSha1PCA3[] =
- {
- 0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
- 0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
- };
- /* PCA 3 secure hash algorithm 512: */
- const unsigned char baSha512PCA3[] =
- {
- 0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
- 0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20,
- 0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e,
- 0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6,
- 0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b,
- 0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b,
- 0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d,
- 0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
- };
- QByteArray pca3sha1 = QByteArray::fromRawData((const char *)baSha1PCA3, sizeof(baSha1PCA3));
- QByteArray pca3sha512 = QByteArray::fromRawData((const char *)baSha512PCA3, sizeof(baSha512PCA3));
-
- /* Verify certificate: */
- return verifyCertificate(pHttp, certificate, pca3sha1, pca3sha512);
-}
-
-/* static */
-int UINetworkReplyPrivateThread::verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512)
-{
- /* Make sure HTTP is created: */
- if (!pHttp)
- return VERR_INVALID_POINTER;
-
- /* Create digest: */
- uint8_t *abSha1;
- size_t cbSha1;
- uint8_t *abSha512;
- size_t cbSha512;
- int rc = RTHttpCertDigest(pHttp, certificate.data(), certificate.size(),
- &abSha1, &cbSha1, &abSha512, &cbSha512);
-
- /* Verify digest: */
- if (cbSha1 != (size_t)sha1.size())
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- else if (memcmp(sha1.constData(), abSha1, cbSha1))
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- if (cbSha512 != (size_t)sha512.size())
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- else if (memcmp(sha512.constData(), abSha512, cbSha512))
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
-
- /* Cleanup digest: */
- RTMemFree(abSha1);
- RTMemFree(abSha512);
-
- /* Return result-code: */
- return rc;
-}
-
-/* static */
-int UINetworkReplyPrivateThread::saveCertificates(const QString &strFullCertificateFileName,
- const QByteArray &certificatePca3G5,
- const QByteArray &certificatePca3)
-{
- /* Open certificates file: */
- QFile file(strFullCertificateFileName);
- bool fFileOpened = file.open(QIODevice::WriteOnly);
- int rc = fFileOpened ? VINF_SUCCESS : VERR_OPEN_FAILED;
-
- /* Save certificates: */
- if (RT_SUCCESS(rc))
- rc = saveCertificate(file, certificatePca3G5);
- if (RT_SUCCESS(rc))
- rc = saveCertificate(file, certificatePca3);
-
- /* Close certificates file: */
- if (fFileOpened)
- file.close();
-
- /* Return result-code: */
- return rc;
-}
-
-/* static */
-int UINetworkReplyPrivateThread::saveCertificate(QFile &file, const QByteArray &certificate)
-{
- /* Save certificate: */
- int rc = VINF_SUCCESS;
- if (RT_SUCCESS(rc))
- rc = file.write(certificate) != -1 ? VINF_SUCCESS : VERR_WRITE_ERROR;
-
- /* Add 'new-line' character: */
- if (RT_SUCCESS(rc))
-#ifdef Q_WS_WIN
- rc = file.write("\r\n") != -1 ? VINF_SUCCESS : VERR_WRITE_ERROR;
-#else /* Q_WS_WIN */
- rc = file.write("\n") != -1 ? VINF_SUCCESS : VERR_WRITE_ERROR;
-#endif /* !Q_WS_WIN */
-
- /* Return result-code: */
+ /*
+ * Look at what we got back and hash it.
+ */
+ rc = VERR_NOT_FOUND;
+ for (PCRTCRPEMSECTION pCur = pSectionHead; pCur; pCur = pCur->pNext)
+ if (pCur->cbData == pWantedCert->cbEncoded)
+ {
+ if ( RTSha1Check(pCur->pbData, pCur->cbData, pWantedCert->abSha1)
+ && RTSha512Check(pCur->pbData, pCur->cbData, pWantedCert->abSha512))
+ {
+ /*
+ * Matching, add it to the store.
+ */
+ rc = RTCrStoreCertAddEncoded(hStore,
+ RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
+ pCur->pbData, pCur->cbData,
+ RTErrInfoInitStatic(&StaticErrInfo));
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ LogRel(("RTCrStoreCertAddEncoded: %s\n", StaticErrInfo.Core.pszMsg));
+ else if (RT_FAILURE(rc))
+ LogRel(("RTCrStoreCertAddEncoded: %Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ break;
+ }
+ else
+ LogRel(("convertVerifyAndAddPemCertificateToStore: hash mismatch (cbData=%#zx)\n", pCur->cbData));
+ }
+ else
+ LogRel(("convertVerifyAndAddPemCertificateToStore: cbData=%#zx expected %#zx\n",
+ pCur->cbData, pWantedCert->cbEncoded));
+
+ RTCrPemFreeSections(pSectionHead);
+ }
return rc;
}
+#ifndef VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS
-/* Our network-reply object: */
+/**
+ * Our network-reply (HTTP) object.
+ */
class UINetworkReplyPrivate : public QObject
{
Q_OBJECT;
@@ -606,6 +735,8 @@ public:
: m_error(QNetworkReply::NoError)
, m_pThread(0)
{
+ /* Prepare full error template: */
+ m_strErrorTemplate = tr("%1: %2", "Context description: Error description");
/* Create and run network-reply thread: */
m_pThread = new UINetworkReplyPrivateThread(request);
connect(m_pThread, SIGNAL(finished()), this, SLOT(sltFinished()));
@@ -636,21 +767,17 @@ public:
{
switch (m_error)
{
- case QNetworkReply::NoError:
- break;
- case QNetworkReply::HostNotFoundError:
- return tr("Host not found");
- case QNetworkReply::ContentAccessDenied:
- return tr("Content access denied");
- case QNetworkReply::ProtocolFailure:
- return tr("Protocol failure");
- case QNetworkReply::AuthenticationRequiredError:
- return tr("Wrong SSL certificate format");
- case QNetworkReply::SslHandshakeFailedError:
- return tr("SSL authentication failed");
- default:
- return tr("Unknown reason");
- break;
+ case QNetworkReply::NoError: break;
+ case QNetworkReply::RemoteHostClosedError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Unable to initialize HTTP library"));
+ case QNetworkReply::HostNotFoundError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Host not found"));
+ case QNetworkReply::ContentAccessDenied: return m_strErrorTemplate.arg(m_pThread->context(), tr("Content access denied"));
+ case QNetworkReply::ProtocolFailure: return m_strErrorTemplate.arg(m_pThread->context(), tr("Protocol failure"));
+ case QNetworkReply::ConnectionRefusedError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Connection refused"));
+ case QNetworkReply::SslHandshakeFailedError: return m_strErrorTemplate.arg(m_pThread->context(), tr("SSL authentication failed"));
+ case QNetworkReply::AuthenticationRequiredError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Wrong SSL certificate format"));
+ case QNetworkReply::ContentReSendError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Content moved"));
+ case QNetworkReply::ProxyNotFoundError: return m_strErrorTemplate.arg(m_pThread->context(), tr("Proxy not found"));
+ default: return m_strErrorTemplate.arg(m_pThread->context(), tr("Unknown reason"));
}
return QString();
}
@@ -665,41 +792,38 @@ private slots:
{
switch (m_pThread->error())
{
- case VINF_SUCCESS:
- m_error = QNetworkReply::NoError;
- break;
- case VERR_HTTP_ABORTED:
- m_error = QNetworkReply::OperationCanceledError;
- break;
- case VERR_HTTP_NOT_FOUND:
- m_error = QNetworkReply::HostNotFoundError;
- break;
- case VERR_HTTP_ACCESS_DENIED:
- m_error = QNetworkReply::ContentAccessDenied;
- break;
- case VERR_HTTP_BAD_REQUEST:
- m_error = QNetworkReply::ProtocolFailure;
- break;
- case VERR_HTTP_CACERT_WRONG_FORMAT:
- m_error = QNetworkReply::AuthenticationRequiredError;
- break;
- case VERR_HTTP_CACERT_CANNOT_AUTHENTICATE:
- m_error = QNetworkReply::SslHandshakeFailedError;
- break;
- default:
- m_error = QNetworkReply::UnknownNetworkError;
- break;
+ case VINF_SUCCESS: m_error = QNetworkReply::NoError; break;
+ case VERR_HTTP_INIT_FAILED: m_error = QNetworkReply::RemoteHostClosedError; break;
+ case VERR_HTTP_NOT_FOUND: m_error = QNetworkReply::HostNotFoundError; break;
+ case VERR_HTTP_ACCESS_DENIED: m_error = QNetworkReply::ContentAccessDenied; break;
+ case VERR_HTTP_BAD_REQUEST: m_error = QNetworkReply::ProtocolFailure; break;
+ case VERR_HTTP_COULDNT_CONNECT: m_error = QNetworkReply::ConnectionRefusedError; break;
+ case VERR_HTTP_SSL_CONNECT_ERROR: m_error = QNetworkReply::SslHandshakeFailedError; break;
+ case VERR_HTTP_CACERT_WRONG_FORMAT: m_error = QNetworkReply::AuthenticationRequiredError; break;
+ case VERR_HTTP_CACERT_CANNOT_AUTHENTICATE: m_error = QNetworkReply::AuthenticationRequiredError; break;
+ case VERR_HTTP_ABORTED: m_error = QNetworkReply::OperationCanceledError; break;
+ case VERR_HTTP_REDIRECTED: m_error = QNetworkReply::ContentReSendError; break;
+ case VERR_HTTP_PROXY_NOT_FOUND: m_error = QNetworkReply::ProxyNotFoundError; break;
+ default: m_error = QNetworkReply::UnknownNetworkError; break;
}
emit finished();
}
private:
+ /** Holds full error template in "Context description: Error description" form. */
+ QString m_strErrorTemplate;
+
/* Variables: */
QNetworkReply::NetworkError m_error;
UINetworkReplyPrivateThread *m_pThread;
};
+
+/*********************************************************************************************************************************
+* Class UINetworkReply implementation. *
+*********************************************************************************************************************************/
+
UINetworkReply::UINetworkReply(const QNetworkRequest &request, UINetworkRequestType requestType)
: m_replyType(UINetworkReplyType_Qt)
, m_pReply(0)
@@ -816,3 +940,5 @@ QUrl UINetworkReply::url() const
#include "UINetworkReply.moc"
+#endif /* !VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS */
+
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequestWidget.cpp b/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequestWidget.cpp
index dd4b206..78186c9 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequestWidget.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequestWidget.cpp
@@ -174,6 +174,10 @@ void UINetworkRequestWidget::sltSetProgressToFailed(const QString &strError)
for (int i = 0; i < links.size(); ++i)
strErrorText = strErrorText.arg(QString("<b>%1</b>").arg(links[i]));
+ // @todo: NLS: Embed <br> directly into error header text.
+ /* Prepend the error-message with <br> symbol: */
+ strErrorText.prepend("<br>");
+
/* Show error label: */
m_pErrorPane->setHidden(false);
m_pErrorPane->setText(UINetworkManagerDialog::tr("The network operation failed with the following error: %1.").arg(strErrorText));
diff --git a/src/VBox/Frontends/VirtualBox/src/net/tstSSLCertDownloads.cpp b/src/VBox/Frontends/VirtualBox/src/net/tstSSLCertDownloads.cpp
new file mode 100644
index 0000000..63a4339
--- /dev/null
+++ b/src/VBox/Frontends/VirtualBox/src/net/tstSSLCertDownloads.cpp
@@ -0,0 +1,165 @@
+/* $Id: tstSSLCertDownloads.cpp $ */
+/** @file
+ * IPRT Testcase - Simple cURL testcase.
+ */
+
+/*
+ * Copyright (C) 2012-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/test.h>
+
+
+/*
+ * It's a private class we're testing, so we must include the source.
+ * Better than emedding the testcase as public function in the class.
+ */
+#include "UINetworkReply.cpp"
+
+
+
+/*static*/ void UINetworkReplyPrivateThread::testIt(RTTEST hTest)
+{
+ QNetworkRequest Dummy;
+ UINetworkReplyPrivateThread TestObj(Dummy);
+
+ /*
+ * Do the first setup things that UINetworkReplyPrivateThread::run.
+ */
+ RTTESTI_CHECK_RC(RTHttpCreate(&TestObj.m_hHttp), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(TestObj.applyProxyRules(), VINF_SUCCESS);
+
+ /*
+ * Duplicate much of downloadMissingCertificates, but making sure we
+ * can both get the certificate from the ZIP file(s) and the first
+ * PEM URL (as the rest are currently busted).
+ */
+ RTTestISub("SSL Cert downloading");
+ RTCRSTORE hStore;
+ RTTESTI_CHECK_RC(RTCrStoreCreateInMem(&hStore, RT_ELEMENTS(s_aCerts) * 2), VINF_SUCCESS);
+
+ int rc;
+
+ /* ZIP files: */
+ for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(s_apszRootsZipUrls); iUrl++)
+ {
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "URL: %s\n", s_apszRootsZipUrls[iUrl]);
+ void *pvRootsZip;
+ size_t cbRootsZip;
+ rc = RTHttpGetBinary(TestObj.m_hHttp, s_apszRootsZipUrls[iUrl], &pvRootsZip, &cbRootsZip);
+ if (RT_SUCCESS(rc))
+ {
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ {
+ CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
+ if (pInfo->pszZipFile)
+ {
+ void *pvFile;
+ size_t cbFile;
+ RTTESTI_CHECK_RC_BREAK(RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, pInfo->pszZipFile),
+ VINF_SUCCESS);
+ RTTESTI_CHECK_RC(convertVerifyAndAddPemCertificateToStore(hStore, pvFile, cbFile, &TestObj.s_aCerts[i]),
+ VINF_SUCCESS);
+ RTMemFree(pvFile);
+ }
+ }
+ RTHttpFreeResponse(pvRootsZip);
+ }
+ else if ( rc != VERR_HTTP_PROXY_NOT_FOUND
+ && rc != VERR_HTTP_COULDNT_CONNECT)
+ RTTestIFailed("%Rrc on '%s'", rc, s_apszRootsZipUrls[iUrl]); /* code or link broken */
+ }
+
+ /* PEM files: */
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+ {
+ uint32_t iUrl = 0; /* First URL must always work. */
+ UINetworkReplyPrivateThread::CERTINFO const *pInfo;
+ pInfo = (UINetworkReplyPrivateThread::CERTINFO const *)s_aCerts[i].pvUser;
+ if (pInfo->apszUrls[iUrl])
+ {
+ RTTestIPrintf(RTTESTLVL_ALWAYS, "URL: %s\n", pInfo->apszUrls[iUrl]);
+ void *pvResponse;
+ size_t cbResponse;
+ rc = RTHttpGetBinary(TestObj.m_hHttp, pInfo->apszUrls[iUrl], &pvResponse, &cbResponse);
+ if (RT_SUCCESS(rc))
+ {
+ RTTESTI_CHECK_RC_OK(convertVerifyAndAddPemCertificateToStore(hStore, pvResponse, cbResponse,
+ &TestObj.s_aCerts[i]));
+ RTHttpFreeResponse(pvResponse);
+ }
+ else if ( rc != VERR_HTTP_PROXY_NOT_FOUND
+ && rc != VERR_HTTP_COULDNT_CONNECT)
+ RTTestIFailed("%Rrc on '%s'", rc, pInfo->apszUrls[iUrl]); /* code or link broken */
+ }
+ }
+
+ RTTESTI_CHECK(RTCrStoreRelease(hStore) == 0);
+
+ /*
+ * Now check the gathering of certificates on the system doesn't crash.
+ */
+ RTTestISub("Refreshing certificates");
+
+ /* create an empty store and do the refresh operation, writing it to /dev/null. */
+ RTTESTI_CHECK_RC(RTCrStoreCreateInMem(&hStore, RT_ELEMENTS(s_aCerts) * 2), VINF_SUCCESS);
+ bool afFoundCerts[RT_ELEMENTS(s_aCerts)];
+ RT_ZERO(afFoundCerts);
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ RTTESTI_CHECK_RC_OK(TestObj.refreshCertificates(NIL_RTHTTP, &hStore, afFoundCerts, "nul"));
+#else
+ RTTESTI_CHECK_RC_OK(TestObj.refreshCertificates(NIL_RTHTTP, &hStore, afFoundCerts, "/dev/null"));
+#endif
+
+ /* Log how many certificates we found and require at least one. */
+ uint32_t cCerts = RTCrStoreCertCount(hStore);
+ RTTestIValue("certificates", cCerts, RTTESTUNIT_NONE);
+ RTTESTI_CHECK(cCerts > 0);
+
+ RTTESTI_CHECK(RTCrStoreRelease(hStore) == 0);
+
+ /*
+ * We're done.
+ */
+ //RTTESTI_CHECK_RC(RTHttpDestroy(TestObj.m_hHttp), VINF_SUCCESS);
+ RTHttpDestroy(TestObj.m_hHttp);
+ TestObj.m_hHttp = NIL_RTHTTP;
+}
+
+
+int main()
+{
+ RTTEST hTest;
+ RTEXITCODE rcExit = RTTestInitAndCreate("tstSSLCertDownloads", &hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(hTest);
+
+ UINetworkReplyPrivateThread::testIt(hTest);
+
+ return RTTestSummaryAndDestroy(hTest);
+}
+
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIFilmContainer.cpp b/src/VBox/Frontends/VirtualBox/src/widgets/UIFilmContainer.cpp
old mode 100644
new mode 100755
diff --git a/src/VBox/GuestHost/OpenGL/error/error.py b/src/VBox/GuestHost/OpenGL/error/error.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py b/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py
old mode 100644
new mode 100755
diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_header.py b/src/VBox/GuestHost/OpenGL/packer/pack_header.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/packer/packer_bbox.py b/src/VBox/GuestHost/OpenGL/packer/packer_bbox.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/dispatch.py b/src/VBox/GuestHost/OpenGL/spu_loader/dispatch.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/dispatchheader.py b/src/VBox/GuestHost/OpenGL/spu_loader/dispatchheader.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py b/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/spuchange.py b/src/VBox/GuestHost/OpenGL/spu_loader/spuchange.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/spucopy.py b/src/VBox/GuestHost/OpenGL/spu_loader/spucopy.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_defs.py b/src/VBox/GuestHost/OpenGL/state_tracker/state_defs.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_funcs.py b/src/VBox/GuestHost/OpenGL/state_tracker/state_funcs.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c
index d111e02..d500298 100644
--- a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c
+++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c
@@ -1006,7 +1006,7 @@ DECLEXPORT(void) STATE_APIENTRY
crStateGLSLProgramCacheUniforms(GLuint program, GLsizei maxcbData, GLsizei *cbData, GLvoid *pData)
{
CRGLSLProgram *pProgram = crStateGetProgramObj(program);
- GLint maxUniformLen, activeUniforms=0, fakeUniformsCount, i, j;
+ GLint maxUniformLen = 0, activeUniforms=0, fakeUniformsCount, i, j;
char *pCurrent = pData;
GLsizei cbWritten;
@@ -1016,8 +1016,13 @@ crStateGLSLProgramCacheUniforms(GLuint program, GLsizei maxcbData, GLsizei *cbDa
return;
}
+ /*
+ * OpenGL spec says about GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ * "If no active uniform variable exist, 0 is returned."
+ */
diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen);
- diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms);
+ if (maxUniformLen > 0)
+ diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms);
*cbData = 0;
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_isenabled.py b/src/VBox/GuestHost/OpenGL/state_tracker/state_isenabled.py
old mode 100755
new mode 100644
diff --git a/src/VBox/GuestHost/OpenGL/util/debug_opcodes.py b/src/VBox/GuestHost/OpenGL/util/debug_opcodes.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostDrivers/Support/Makefile.kmk b/src/VBox/HostDrivers/Support/Makefile.kmk
index 993628a..45c69a1 100644
--- a/src/VBox/HostDrivers/Support/Makefile.kmk
+++ b/src/VBox/HostDrivers/Support/Makefile.kmk
@@ -601,6 +601,9 @@ if1of ($(KBUILD_TARGET), darwin linux solaris win)
ifdef VBOX_WITH_HARDENING
VBoxDrv_ASDEFS += VBOX_WITH_HARDENING
endif
+ #if ($(VBOX_VERSION_BUILD) % 2) == 1
+ # VBoxDrv_DEFS += VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
+ #endif
VBoxDrv_INCS = . $(VBoxDrv_0_OUTDIR)
VBoxDrv_INCS.darwin = ./darwin
@@ -716,11 +719,11 @@ if1of ($(KBUILD_TARGET), linux)
$$(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
+ $(QUIET)$(SED) -e "" \
+ $(if-expr !defined(VBOX_WITH_HARDENING) ,-e "s;-DVBOX_WITH_HARDENING;;g",) \
+ $(if-expr ($(VBOX_VERSION_BUILD) % 2) == 0 || 1 \
+ , -e "s;-DVBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV;;g" -e "s;-DIPRT_WITH_EFLAGS_AC_PRESERVING;;g",) \
+ --output $@ $<
%$(QUIET2)$(APPEND) -t '$(PATH_TARGET)/vboxdrv-mod-1.dep' 'Support/linux/Makefile_VBOX_HARDENED=$(VBOX_WITH_HARDENING)'
endif # real linux
diff --git a/src/VBox/HostDrivers/Support/SUPDrv.c b/src/VBox/HostDrivers/Support/SUPDrv.c
index e53bba9..8563dae 100644
--- a/src/VBox/HostDrivers/Support/SUPDrv.c
+++ b/src/VBox/HostDrivers/Support/SUPDrv.c
@@ -106,6 +106,32 @@
# define DO_NOT_START_GIP
#endif
+/** @ SUPDRV_CHECK_SMAP_SETUP
+ * SMAP check setup. */
+/** @def SUPDRV_CHECK_SMAP_CHECK
+ * Checks that the AC flag is set if SMAP is enabled. If AC is not set, it
+ * will be logged and @a a_BadExpr is executed. */
+#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
+# define SUPDRV_CHECK_SMAP_SETUP() uint32_t const fKernelFeatures = SUPR0GetKernelFeatures()
+# define SUPDRV_CHECK_SMAP_CHECK(a_pDevExt, a_BadExpr) \
+ do { \
+ if (fKernelFeatures & SUPKERNELFEATURES_SMAP) \
+ { \
+ RTCCUINTREG fEfl = ASMGetFlags(); \
+ if (RT_LIKELY(fEfl & X86_EFL_AC)) \
+ { /* likely */ } \
+ else \
+ { \
+ supdrvBadContext(a_pDevExt, "SUPDrv.cpp", __LINE__, "EFLAGS.AC is 0!"); \
+ a_BadExpr; \
+ } \
+ } \
+ } while (0)
+#else
+# define SUPDRV_CHECK_SMAP_SETUP() uint32_t const fKernelFeatures = 0
+# define SUPDRV_CHECK_SMAP_CHECK(a_pDevExt, a_BadExpr) NOREF(fKernelFeatures)
+#endif
+
/*******************************************************************************
* Internal Functions *
@@ -174,6 +200,7 @@ static SUPFUNC g_aFunctions[] =
/* Normal function pointers: */
{ "g_pSUPGlobalInfoPage", (void *)&g_pSUPGlobalInfoPage }, /* SED: DATA */
{ "SUPGetGIP", (void *)SUPGetGIP },
+ { "SUPR0BadContext", (void *)SUPR0BadContext },
{ "SUPR0ComponentDeregisterFactory", (void *)SUPR0ComponentDeregisterFactory },
{ "SUPR0ComponentQueryFactory", (void *)SUPR0ComponentQueryFactory },
{ "SUPR0ComponentRegisterFactory", (void *)SUPR0ComponentRegisterFactory },
@@ -3549,6 +3576,66 @@ SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3)
/**
+ * Reports a bad context, currenctly that means EFLAGS.AC is 0 instead of 1.
+ *
+ * @param pSession The session of the caller.
+ * @param pszFile The source file where the caller detected the bad
+ * context.
+ * @param uLine The line number in @a pszFile.
+ * @param pszExtra Optional additional message to give further hints.
+ */
+void VBOXCALL supdrvBadContext(PSUPDRVDEVEXT pDevExt, const char *pszFile, uint32_t uLine, const char *pszExtra)
+{
+ uint32_t cCalls;
+
+ /*
+ * Shorten the filename before displaying the message.
+ */
+ for (;;)
+ {
+ const char *pszTmp = strchr(pszFile, '/');
+ if (!pszTmp)
+ pszTmp = strchr(pszFile, '\\');
+ if (!pszTmp)
+ break;
+ pszFile = pszTmp + 1;
+ }
+ if (RT_VALID_PTR(pszExtra) && *pszExtra)
+ SUPR0Printf("vboxdrv: Bad CPU context error at line %u in %s: %s\n", uLine, pszFile, pszExtra);
+ else
+ SUPR0Printf("vboxdrv: Bad CPU context error at line %u in %s!\n", uLine, pszFile);
+
+ /*
+ * Record the incident so that we stand a chance of blocking I/O controls
+ * before panicing the system.
+ */
+ cCalls = ASMAtomicIncU32(&pDevExt->cBadContextCalls);
+ if (cCalls > UINT32_MAX - _1K)
+ ASMAtomicWriteU32(&pDevExt->cBadContextCalls, UINT32_MAX - _1K);
+}
+
+
+/**
+ * Reports a bad context, currenctly that means EFLAGS.AC is 0 instead of 1.
+ *
+ * @param pSession The session of the caller.
+ * @param pszFile The source file where the caller detected the bad
+ * context.
+ * @param uLine The line number in @a pszFile.
+ * @param pszExtra Optional additional message to give further hints.
+ */
+SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExtra)
+{
+ PSUPDRVDEVEXT pDevExt;
+
+ AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
+ pDevExt = pSession->pDevExt;
+
+ supdrvBadContext(pDevExt, pszFile, uLine, pszExtra);
+}
+
+
+/**
* Gets the paging mode of the current CPU.
*
* @returns Paging mode, SUPPAGEINGMODE_INVALID on error.
@@ -4521,12 +4608,15 @@ static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
PSUPDRVLDRIMAGE pImage;
void *pv;
size_t cchName = strlen(pReq->u.In.szName); /* (caller checked < 32). */
+ SUPDRV_CHECK_SMAP_SETUP();
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
LogFlow(("supdrvIOCtl_LdrOpen: szName=%s cbImageWithTabs=%d\n", pReq->u.In.szName, pReq->u.In.cbImageWithTabs));
/*
* Check if we got an instance of the image already.
*/
supdrvLdrLock(pDevExt);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
for (pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
{
if ( pImage->szName[cchName] == '\0'
@@ -4541,6 +4631,7 @@ static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
pReq->u.Out.fNativeLoader = pImage->fNative;
supdrvLdrAddUsage(pSession, pImage);
supdrvLdrUnlock(pDevExt);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
return VINF_SUCCESS;
}
supdrvLdrUnlock(pDevExt);
@@ -4569,6 +4660,7 @@ static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
Log(("supdrvIOCtl_LdrOpen: RTMemAlloc() failed\n"));
return /*VERR_NO_MEMORY*/ VERR_INTERNAL_ERROR_2;
}
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
/*
* Setup and link in the LDR stuff.
@@ -4602,6 +4694,7 @@ static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
pImage->pvImage = RT_ALIGN_P(pImage->pvImageAlloc, 32);
pImage->fNative = false;
rc = pImage->pvImageAlloc ? VINF_SUCCESS : VERR_NO_EXEC_MEMORY;
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
}
if (RT_FAILURE(rc))
{
@@ -4626,6 +4719,7 @@ static int supdrvIOCtl_LdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
supdrvOSLdrNotifyOpened(pDevExt, pImage);
supdrvLdrUnlock(pDevExt);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
return VINF_SUCCESS;
}
@@ -4685,12 +4779,16 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
PSUPDRVLDRUSAGE pUsage;
PSUPDRVLDRIMAGE pImage;
int rc;
+ SUPDRV_CHECK_SMAP_SETUP();
LogFlow(("supdrvIOCtl_LdrLoad: pvImageBase=%p cbImageWithBits=%d\n", pReq->u.In.pvImageBase, pReq->u.In.cbImageWithTabs));
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
/*
* Find the ldr image.
*/
supdrvLdrLock(pDevExt);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
+
pUsage = pSession->pLdrUsage;
while (pUsage && pUsage->pImage->pvImage != pReq->u.In.pvImageBase)
pUsage = pUsage->pNext;
@@ -4778,6 +4876,7 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
rc = supdrvLdrValidatePointer(pDevExt, pImage, pReq->u.In.pfnModuleTerm, true, pReq->u.In.abImage, "pfnModuleTerm");
if (RT_FAILURE(rc))
return rc;
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
/*
* Allocate and copy the tables.
@@ -4791,6 +4890,7 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
memcpy(pImage->pachStrTab, &pReq->u.In.abImage[pReq->u.In.offStrTab], pImage->cbStrTab);
else
rc = /*VERR_NO_MEMORY*/ VERR_INTERNAL_ERROR_3;
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
}
pImage->cSymbols = pReq->u.In.cSymbols;
@@ -4802,6 +4902,7 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
memcpy(pImage->paSymbols, &pReq->u.In.abImage[pReq->u.In.offSymbols], cbSymbols);
else
rc = /*VERR_NO_MEMORY*/ VERR_INTERNAL_ERROR_4;
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
}
/*
@@ -4820,6 +4921,7 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
memcpy(pImage->pvImage, &pReq->u.In.abImage[0], pImage->cbImageBits);
Log(("vboxdrv: Loaded '%s' at %p\n", pImage->szName, pImage->pvImage));
}
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
}
/*
@@ -4853,7 +4955,9 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
Log(("supdrvIOCtl_LdrLoad: calling pfnModuleInit=%p\n", pImage->pfnModuleInit));
pDevExt->pLdrInitImage = pImage;
pDevExt->hLdrInitThread = RTThreadNativeSelf();
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
rc = pImage->pfnModuleInit(pImage);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
pDevExt->pLdrInitImage = NULL;
pDevExt->hLdrInitThread = NIL_RTNATIVETHREAD;
if (RT_FAILURE(rc) && pDevExt->pvVMMR0 == pImage->pvImage)
@@ -4878,6 +4982,7 @@ static int supdrvIOCtl_LdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, P
}
supdrvLdrUnlock(pDevExt);
+ SUPDRV_CHECK_SMAP_CHECK(pDevExt, RT_NOTHING);
return rc;
}
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIOC.h b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
index 8b1c865..412c88a 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvIOC.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
@@ -1,4 +1,4 @@
-/* $Revision: 98806 $ */
+/* $Revision: 103349 $ */
/** @file
* VirtualBox Support Driver - IOCtl definitions.
*/
@@ -210,7 +210,7 @@ typedef SUPREQHDR *PSUPREQHDR;
* @todo Pending work on next major version change:
* - Remove RTSpinlockReleaseNoInts.
*/
-#define SUPDRV_IOC_VERSION 0x001a000a
+#define SUPDRV_IOC_VERSION 0x001a000b
/** SUP_IOCTL_COOKIE. */
typedef struct SUPCOOKIE
diff --git a/src/VBox/HostDrivers/Support/SUPDrvInternal.h b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
index 34476b7..bbf018e 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvInternal.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
@@ -561,6 +561,9 @@ typedef struct SUPDRVDEVEXT
RTNATIVETHREAD volatile hLdrInitThread;
/** @} */
+ /** Number of times someone reported bad execution context via SUPR0BadContext.
+ * (This is times EFLAGS.AC is zero when we expected it to be 1.) */
+ uint32_t volatile cBadContextCalls;
/** GIP mutex.
* Any changes to any of the GIP members requires ownership of this mutex,
@@ -774,6 +777,7 @@ PSUPDRVSESSION VBOXCALL supdrvSessionHashTabLookup(PSUPDRVDEVEXT pDevExt, RTPROC
PSUPDRVSESSION *ppOsSessionPtr);
uint32_t VBOXCALL supdrvSessionRetain(PSUPDRVSESSION pSession);
uint32_t VBOXCALL supdrvSessionRelease(PSUPDRVSESSION pSession);
+void VBOXCALL supdrvBadContext(PSUPDRVDEVEXT pDevExt, const char *pszFile, uint32_t uLine, const char *pszExtra);
int VBOXCALL supdrvQueryVTCapsInternal(uint32_t *pfCaps);
int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt);
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
index c019fcb..a6632d3 100644
--- a/src/VBox/HostDrivers/Support/SUPLib.cpp
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -279,7 +279,7 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x001a0000
- ? 0x001a000a
+ ? 0x001a000b
: SUPDRV_IOC_VERSION & 0xffff0000;
CookieReq.u.In.u32MinVersion = uMinVersion;
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
index 04b2331..59ab5f1 100644
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
@@ -968,7 +968,7 @@ extern "C" uint32_t g_uNtVerCombined;
DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
{
- static const char s_szLogOption[] = "--sup-startup-log=";
+ static const char s_szLogOption[] = "--sup-hardening-log=";
/*
* Scan the argument vector.
diff --git a/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp b/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp
index 7b62768..720b867 100644
--- a/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp
+++ b/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp
@@ -28,16 +28,7 @@
* 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 "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
#include "../SUPDrvInternal.h"
#include <VBox/version.h>
@@ -78,6 +69,17 @@ RT_C_DECLS_BEGIN
RT_C_DECLS_END
#endif
+/* The following macros are duplicated in the-darwin-kernel.h. */
+#define IPRT_DARWIN_SAVE_EFL_AC() RTCCUINTREG const fSavedEfl = ASMGetFlags();
+#define IPRT_DARWIN_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
+#define IPRT_DARWIN_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~X86_EFL_AC, fSavedEfl & X86_EFL_AC)
+
+
+/* Temporary debugging - very temporary... */
+#define VBOX_PROC_SELFNAME_LEN (20)
+#define VBOX_RETRIEVE_CUR_PROC_NAME(_name) char _name[VBOX_PROC_SELFNAME_LEN]; \
+ proc_selfname(pszProcName, VBOX_PROC_SELFNAME_LEN)
+
/*******************************************************************************
* Defined Constants And Macros *
@@ -448,7 +450,7 @@ static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *p
* The process issuing the request must be the current process.
*/
RTPROCESS Process = RTProcSelf();
- if (Process != proc_pid(pProcess))
+ if ((int)Process != proc_pid(pProcess))
return EIO;
/*
@@ -544,6 +546,20 @@ static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags,
const unsigned iHash = SESSION_HASH(Process);
PSUPDRVSESSION pSession;
+#ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
+ /*
+ * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
+ *
+ * This isn't a problem, as there is absolutely nothing in the kernel context that
+ * depend on user context triggering cleanups. That would be pretty wild, right?
+ */
+ if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
+ {
+ SUPR0Printf("VBoxDrvDarwinIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
+ return EDEVERR;
+ }
+#endif
+
/*
* Find the session.
*/
@@ -598,10 +614,25 @@ static int VBoxDrvDarwinIOCtlSMAP(dev_t Dev, u_long iCmd, caddr_t pData, int fFl
* Allow VBox R0 code to touch R3 memory. Setting the AC bit disables the
* SMAP check.
*/
- RTCCUINTREG uFlags = ASMGetFlags();
- ASMSetAC();
+ RTCCUINTREG fSavedEfl = ASMAddFlags(X86_EFL_AC);
+
int rc = VBoxDrvDarwinIOCtl(Dev, iCmd, pData, fFlags, pProcess);
- ASMSetFlags(uFlags);
+
+#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ /*
+ * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
+ * accidentially modified it or some other important flag.
+ */
+ if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL))
+ != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL)) | X86_EFL_AC) ))
+ {
+ char szTmp[48];
+ RTStrPrintf(szTmp, sizeof(szTmp), "iCmd=%#x: %#x->%#x!", iCmd, (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
+ supdrvBadContext(&g_DevExt, "SUPDrv-darwin.cpp", __LINE__, szTmp);
+ }
+#endif
+
+ ASMSetFlags(fSavedEfl);
return rc;
}
@@ -654,17 +685,20 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
/*
* Get the header and figure out how much we're gonna have to read.
*/
+ IPRT_DARWIN_SAVE_EFL_AC();
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));
+ IPRT_DARWIN_RESTORE_EFL_AC();
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));
+ IPRT_DARWIN_SAVE_EFL_AC();
return EINVAL;
}
cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
@@ -673,6 +707,7 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
|| cbReq > _1M*16))
{
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
+ IPRT_DARWIN_SAVE_EFL_AC();
return EINVAL;
}
@@ -685,6 +720,7 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
if (RT_UNLIKELY(!pHdr))
{
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return ENOMEM;
}
rc = copyin(pUser, pHdr, Hdr.cbIn);
@@ -696,10 +732,12 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
else
RTMemTmpFree(pHdr);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
if (Hdr.cbIn < cbReq)
RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbReq - Hdr.cbIn);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
else
{
@@ -718,6 +756,7 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
*/
if (pUser)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
uint32_t cbOut = pHdr->cbOut;
if (cbOut > cbReq)
{
@@ -734,6 +773,7 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
else
RTMemTmpFree(pHdr);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
}
else
@@ -744,7 +784,11 @@ static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t
if (pUser)
{
if (pvPageBuf)
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ }
else
RTMemTmpFree(pHdr);
}
@@ -894,6 +938,7 @@ int VBOXCALL supdrvOSEnableVTx(bool fEnable)
&& g_pfnVmxResume
&& g_pVmxUseCount)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
if (fEnable)
{
/*
@@ -917,7 +962,10 @@ int VBOXCALL supdrvOSEnableVTx(bool fEnable)
rc = VERR_VMX_NO_VMX;
}
if (RT_FAILURE(rc))
+ {
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
+ }
}
g_fDoneCleanup = true;
}
@@ -953,6 +1001,7 @@ int VBOXCALL supdrvOSEnableVTx(bool fEnable)
rc = VINF_SUCCESS;
LogRel(("VBoxDrv: host_vmxoff -> vmx_use_count=%d\n", *g_pVmxUseCount));
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
else
{
@@ -983,7 +1032,9 @@ bool VBOXCALL supdrvOSSuspendVTxOnCpu(void)
if ( g_pVmxUseCount
&& *g_pVmxUseCount > 0)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
g_pfnVmxSuspend();
+ IPRT_DARWIN_RESTORE_EFL_AC();
return true;
}
return false;
@@ -1006,7 +1057,11 @@ void VBOXCALL supdrvOSResumeVTxOnCpu(bool fSuspended)
*/
if ( fSuspended
&& g_pfnVmxResume)
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
g_pfnVmxResume();
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ }
else
Assert(!fSuspended);
#else
@@ -1135,9 +1190,10 @@ static void supdrvDarwinResumeBuiltinKbd(void)
*/
int VBOXCALL supdrvDarwinResumeSuspendedKbds(void)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
supdrvDarwinResumeBuiltinKbd();
supdrvDarwinResumeBluetoothKbd();
-
+ IPRT_DARWIN_RESTORE_EFL_AC();
return 0;
}
@@ -1167,6 +1223,7 @@ static int VBoxDrvDarwinErr2DarwinErr(int rc)
return EPERM;
}
+
/**
* Check if the CPU has SMAP support.
*/
@@ -1181,11 +1238,17 @@ static bool vboxdrvDarwinCpuHasSMAP(void)
if (uEBX & X86_CPUID_STEXT_FEATURE_EBX_SMAP)
return true;
}
+#ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
+ return true;
+#else
return false;
+#endif
}
+
RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
va_list va;
char szMsg[512];
@@ -1195,16 +1258,20 @@ RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
szMsg[sizeof(szMsg) - 1] = '\0';
printf("%s", szMsg);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return 0;
}
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
- return 0;
+ uint32_t fFlags = 0;
+ if (g_DevCW.d_ioctl == VBoxDrvDarwinIOCtlSMAP)
+ fFlags |= SUPKERNELFEATURES_SMAP;
+ else
+ Assert(!(ASMGetCR4() & X86_CR4_SMAP));
+ return fFlags;
}
diff --git a/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c b/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
index ce99717..a7c57b9 100644
--- a/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
+++ b/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c
@@ -588,9 +588,6 @@ SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
}
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
return 0;
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
index 820adfe..6023499 100644
--- a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
+++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
@@ -1,4 +1,4 @@
-/* $Rev: 99005 $ */
+/* $Rev: 103355 $ */
/** @file
* VBoxDrv - The VirtualBox Support Driver - Linux specifics.
*/
@@ -85,12 +85,20 @@
# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
#endif
-/* to include the version number of VirtualBox into kernel backtraces */
+/* We cannot include x86.h, so we copy the defines we need here: */
+#define X86_EFL_IF RT_BIT(9)
+#define X86_EFL_AC RT_BIT(18)
+#define X86_EFL_DF RT_BIT(10)
+#define X86_EFL_IOPL (RT_BIT(12) | RT_BIT(13))
+
+/* To include the version number of VirtualBox into kernel backtraces: */
#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
RT_CONCAT(VBOX_VERSION_MINOR, _), \
VBOX_VERSION_BUILD)
#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
+
+
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
@@ -438,9 +446,7 @@ static int __init VBoxDrvLinuxInit(void)
*/
static void __exit VBoxDrvLinuxUnload(void)
{
- int rc;
Log(("VBoxDrvLinuxUnload\n"));
- NOREF(rc);
#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
platform_device_unregister(&gPlatformDevice);
@@ -452,16 +458,8 @@ static void __exit VBoxDrvLinuxUnload(void)
* opened, at least we'll blindly assume that here.
*/
#ifdef CONFIG_VBOXDRV_AS_MISC
- rc = misc_deregister(&gMiscDeviceUsr);
- if (rc < 0)
- {
- Log(("misc_deregister failed with rc=%#x on vboxdrvu\n", rc));
- }
- rc = misc_deregister(&gMiscDeviceSys);
- if (rc < 0)
- {
- Log(("misc_deregister failed with rc=%#x on vboxdrv\n", rc));
- }
+ misc_deregister(&gMiscDeviceUsr);
+ misc_deregister(&gMiscDeviceSys);
#else /* !CONFIG_VBOXDRV_AS_MISC */
# ifdef CONFIG_DEVFS_FS
/*
@@ -624,6 +622,25 @@ static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned
{
PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
int rc;
+#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ RTCCUINTREG fSavedEfl;
+
+ /*
+ * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
+ *
+ * This isn't a problem, as there is absolutely nothing in the kernel context that
+ * depend on user context triggering cleanups. That would be pretty wild, right?
+ */
+ if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
+ {
+ SUPR0Printf("VBoxDrvDarwinIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
+ return ESPIPE;
+ }
+
+ fSavedEfl = ASMAddFlags(X86_EFL_AC);
+# else
+ stac();
+# endif
/*
* Deal with the two high-speed IOCtl that takes it's arguments from
@@ -634,14 +651,9 @@ static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned
|| uCmd == SUP_IOCTL_FAST_DO_HM_RUN
|| uCmd == SUP_IOCTL_FAST_DO_NOP)
&& pSession->fUnrestricted == true))
- {
- stac();
rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
- clac();
- return rc;
- }
- return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
-
+ else
+ rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
#else /* !HAVE_UNLOCKED_IOCTL */
unlock_kernel();
if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
@@ -652,8 +664,25 @@ static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned
else
rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
lock_kernel();
- return rc;
#endif /* !HAVE_UNLOCKED_IOCTL */
+
+#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ /*
+ * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
+ * accidentially modified it or some other important flag.
+ */
+ if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL))
+ != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL)) | X86_EFL_AC) ))
+ {
+ char szTmp[48];
+ RTStrPrintf(szTmp, sizeof(szTmp), "uCmd=%#x: %#x->%#x!", _IOC_NR(uCmd), (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
+ supdrvBadContext(&g_DevExt, "SUPDrv-linux.c", __LINE__, szTmp);
+ }
+ ASMSetFlags(fSavedEfl);
+#else
+ clac();
+#endif
+ return rc;
}
@@ -677,7 +706,7 @@ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned
/*
* Read the header.
*/
- if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
+ if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
{
Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
return -EFAULT;
@@ -708,7 +737,7 @@ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned
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)))
+ if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
{
Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
RTMemFree(pHdr);
@@ -720,9 +749,7 @@ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned
/*
* Process the IOCtl.
*/
- stac();
rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
- clac();
/*
* Copy ioctl data and output buffer back to user space.
@@ -735,7 +762,7 @@ static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned
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)))
+ if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
{
/* this is really bad! */
OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
@@ -931,6 +958,7 @@ RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
{
va_list va;
char szMsg[512];
+ IPRT_LINUX_SAVE_EFL_AC();
va_start(va, pszFormat);
RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
@@ -938,19 +966,24 @@ RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
szMsg[sizeof(szMsg) - 1] = '\0';
printk("%s", szMsg);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return 0;
}
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
uint32_t fFlags = 0;
#ifdef CONFIG_PAX_KERNEXEC
fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
#endif
+#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ fFlags |= SUPKERNELFEATURES_SMAP;
+#elif defined(CONFIG_X86_SMAP)
+ if (ASMGetCR4() & X86_CR4_SMAP)
+ fFlags |= SUPKERNELFEATURES_SMAP;
+#endif
return fFlags;
}
diff --git a/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp
index 69be647..5d65390 100644
--- a/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp
+++ b/src/VBox/HostDrivers/Support/os2/SUPDrv-os2.cpp
@@ -482,9 +482,6 @@ SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
}
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
return 0;
diff --git a/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c
index c70df61..f15e4d7 100644
--- a/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c
+++ b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c
@@ -1226,9 +1226,6 @@ RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
}
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
return 0;
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
index 1304494..4f1da98 100644
--- a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
@@ -155,7 +155,7 @@ typedef struct SUPDRVNTERRORINFO
/** Number of bytes of valid info. */
uint32_t cchErrorInfo;
/** The error info. */
- char szErrorInfo[2048];
+ char szErrorInfo[16384 - sizeof(RTLISTNODE) - sizeof(HANDLE)*2 - sizeof(uint64_t) - sizeof(uint32_t) - 0x20];
} SUPDRVNTERRORINFO;
/** Pointer to error info. */
typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
@@ -206,6 +206,8 @@ typedef struct SUPDRVNTPROTECT
uint32_t volatile cRefs;
/** The kind of process we're protecting. */
SUPDRVNTPROTECTKIND volatile enmProcessKind;
+ /** Whether this structure is in the tree. */
+ bool fInTree : 1;
/** 7,: Hack to allow the supid themes service duplicate handle privileges to
* our process. */
bool fThemesFirstProcessCreateHandle : 1;
@@ -845,14 +847,14 @@ NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
LogRel(("vboxdrv: %p is not a budding VM process (enmProcessKind=%d).\n",
PsGetProcessId(PsGetCurrentProcess()), pNtProtect->enmProcessKind));
- rc = VERR_ACCESS_DENIED;
+ rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2;
}
supdrvNtProtectRelease(pNtProtect);
}
else
{
LogRel(("vboxdrv: %p is not a budding VM process.\n", PsGetProcessId(PsGetCurrentProcess())));
- rc = VERR_ACCESS_DENIED;
+ rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1;
}
}
/*
@@ -1478,7 +1480,7 @@ NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
/*
* Did we find error info and is the caller requesting data within it?
- * If so, cehck the destination buffer and copy the data into it.
+ * If so, check the destination buffer and copy the data into it.
*/
if ( pCur
&& pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
@@ -1488,12 +1490,11 @@ NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
if (pvDstBuf)
{
uint32_t offRead = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
- uint32_t cbToRead = pCur->cchErrorInfo - (uint32_t)offRead;
- if (cbToRead > pStack->Parameters.Read.Length)
- {
- cbToRead = pStack->Parameters.Read.Length;
+ uint32_t cbToRead = pCur->cchErrorInfo - offRead;
+ if (cbToRead < pStack->Parameters.Read.Length)
RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
- }
+ else
+ cbToRead = pStack->Parameters.Read.Length;
memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
pIrp->IoStatus.Information = cbToRead;
@@ -1521,6 +1522,15 @@ NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
}
else
rcNt = STATUS_UNSUCCESSFUL;
+
+ /* Paranoia: Clear the buffer on failure. */
+ if (!NT_SUCCESS(rcNt))
+ {
+ PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
+ if ( pvDstBuf
+ && pStack->Parameters.Read.Length)
+ RT_BZERO(pvDstBuf, pStack->Parameters.Read.Length);
+ }
}
else
rcNt = STATUS_INVALID_PARAMETER;
@@ -1852,25 +1862,44 @@ int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, c
return VINF_SUCCESS;
/*
- * However, on Windows Server 2003 (sp2 x86) both import thunk tables
- * are fixed up and we typically get a mismatch in the INIT section.
+ * On Windows 10 the ImageBase member of the optional header is sometimes
+ * updated with the actual load address and sometimes not. Try compare
+ *
+ */
+ uint32_t const offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
+ ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
+ : 0;
+ AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
+ IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
+ IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
+
+ uint32_t const offImageBase = offNtHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
+ uint32_t const cbImageBase = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
+ if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
+ && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
+ || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage)
+ && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
+ && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
+ && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
+ && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
+ pbImageBits + offImageBase + cbImageBase,
+ pImage->cbImageBits - offImageBase - cbImageBase))
+ return VINF_SUCCESS;
+
+ /*
+ * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
+ * up and we typically get a mismatch in the INIT section.
*
* So, lets see if everything matches when excluding the
- * OriginalFirstThunk tables. To make life simpler, set the max number
- * of imports to 16 and just record and sort the locations that needs
- * to be excluded from the comparison.
+ * OriginalFirstThunk tables and (maybe) the ImageBase member.
+ * For simplicity the max number of exclusion regions is set to 16.
*/
- IMAGE_NT_HEADERS const *pNtHdrs;
- pNtHdrs = (IMAGE_NT_HEADERS const *)(pbImageBits
- + ( *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
- ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
- : 0));
- if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
- && pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
- && pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
- && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
- && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
- && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
+ if ( pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
+ && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
+ && pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
+ && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
+ && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
+ && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
)
{
struct MyRegion
@@ -1879,11 +1908,23 @@ int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, c
uint32_t cb;
} aExcludeRgns[16];
unsigned cExcludeRgns = 0;
- uint32_t cImpsLeft = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
+
+ /* ImageBase: */
+ if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
+ && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
+ || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
+ {
+ aExcludeRgns[cExcludeRgns].uRva = offImageBase;
+ aExcludeRgns[cExcludeRgns].cb = cbImageBase;
+ cExcludeRgns++;
+ }
+
+ /* Imports: */
+ uint32_t cImpsLeft = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
/ sizeof(IMAGE_IMPORT_DESCRIPTOR);
- IMAGE_IMPORT_DESCRIPTOR const *pImp;
- pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits
- + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+ uint32_t offImps = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
+ IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
while ( cImpsLeft-- > 0
&& cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
{
@@ -2013,9 +2054,6 @@ SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
#endif
-/**
- * Returns configuration flags of the host kernel.
- */
SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
{
return 0;
@@ -2692,6 +2730,7 @@ static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE
bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
if (fSuccess)
{
+ pNtChild->fInTree = true;
pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
pNtChild->u.pParent = pNtParent;
@@ -3022,6 +3061,8 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
#endif
else
{
+ ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
+
/* Special case 1 on Vista, 7 & 8:
The CreateProcess code passes the handle over to CSRSS.EXE
and the code inBaseSrvCreateProcess will duplicate the
@@ -3038,7 +3079,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
&& ExGetPreviousMode() != KernelMode)
{
if ( !pOpInfo->KernelHandle
- && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
+ && fDesiredAccess == s_fCsrssStupidDesires)
{
if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
fAllowedRights |= s_fCsrssStupidDesires;
@@ -3067,7 +3108,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
&& supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
{
pNtProtect->fCsrssFirstProcessCreateHandle = false;
- if (pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
+ if (fDesiredAccess == s_fCsrssStupidDesires)
{
/* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
PROCESS_CREATE_PROCESS */
@@ -3087,7 +3128,7 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
go into making this more secure. */
if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
&& g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
- && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
+ && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
&& pNtProtect->fThemesFirstProcessCreateHandle
&& pOpInfo->KernelHandle == 0
&& ExGetPreviousMode() == UserMode
@@ -3098,11 +3139,29 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
pOpInfo->CallContext = NULL; /* don't assert this. */
}
+ /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
+ PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
+ some myserious and weirdly placed cpu set management of our process.
+ I'd love to understand what that's all about...
+ Currently playing safe and only grand this right, however limited, to
+ audiodg.exe. */
+ if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
+ && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
+ || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
+ || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
+ )
+ && pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
+ && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
+ {
+ fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
+ pOpInfo->CallContext = NULL; /* don't assert this. */
+ }
+
Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
- pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
- pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
- pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
+ fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
+ fAllowedRights, fDesiredAccess & fAllowedRights,
PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
@@ -3127,13 +3186,15 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
}
else
{
+ ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
+
/* Special case 5 on Vista, 7 & 8:
This is the CSRSS.EXE end of special case #1. */
if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
&& pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
&& pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
&& pOpInfo->KernelHandle == 0
- && pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess == s_fCsrssStupidDesires
+ && fDesiredAccess == s_fCsrssStupidDesires
&& pNtProtect->hParentPid
== PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
&& pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
@@ -3153,12 +3214,26 @@ supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMA
}
}
+ /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
+ if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
+ && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
+ || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
+ || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
+ )
+ && pOpInfo->KernelHandle == 0
+ && ExGetPreviousMode() == UserMode
+ && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
+ {
+ fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
+ pOpInfo->CallContext = NULL; /* don't assert this. */
+ }
+
Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
- pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
+ fDesiredAccess,
pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
PsGetProcessImageFileName(PsGetCurrentProcess()) ));
@@ -3439,6 +3514,7 @@ static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUP
{
RTSpinlockAcquire(g_hNtProtectLock);
bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
+ pNtProtect->fInTree = fSuccess;
RTSpinlockRelease(g_hNtProtectLock);
if (!fSuccess)
@@ -3479,9 +3555,13 @@ static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
* child/parent references related to this protection structure.
*/
ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
- PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
+ if (pNtProtect->fInTree)
+ {
+ PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
+ Assert(pRemoved == pNtProtect);
+ pNtProtect->fInTree = false;
+ }
- PSUPDRVNTPROTECT pRemovedChild = NULL;
PSUPDRVNTPROTECT pChild = NULL;
if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
{
@@ -3493,7 +3573,15 @@ static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
if (!cChildRefs)
- pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
+ {
+ Assert(pChild->fInTree);
+ if (pChild->fInTree)
+ {
+ PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
+ Assert(pRemovedChild == pChild);
+ pChild->fInTree = false;
+ }
+ }
else
pChild = NULL;
}
@@ -3502,8 +3590,6 @@ static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
RTSpinlockRelease(g_hNtProtectLock);
- Assert(pRemoved == pNtProtect);
- Assert(pRemovedChild == pChild);
if (pNtProtect->pCsrssProcess)
{
@@ -3731,7 +3817,7 @@ static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNt
Windows 8.1 and later, and one in earlier. This is probably a
little overly paranoid as I think we can safely trust the
system process... */
- if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? 2 : 1)
+ if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
&& pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
{
cSystemProcessHandles++;
@@ -3927,8 +4013,7 @@ static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
if (!pErrorInfo->cchErrorInfo)
pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
"supdrvNtProtectVerifyProcess: rc=%d", rc);
- if (RT_FAILURE(rc))
- RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
+ RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
if (RT_SUCCESS(rc2))
diff --git a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
index fc36616..4414839 100644
--- a/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyImage-win.cpp
@@ -782,7 +782,7 @@ static int supHardNtViCheckIfNotSignedOk(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, u
if (supHardViUtf16PathIsEqual(pwsz, "apisetschema.dll"))
return IS_W70() ? VINF_LDRVI_NOT_SIGNED : rc;
if (supHardViUtf16PathIsEqual(pwsz, "apphelp.dll"))
- return uNtVer < SUP_MAKE_NT_VER_SIMPLE(6, 4) ? VINF_LDRVI_NOT_SIGNED : rc;
+ return VINF_LDRVI_NOT_SIGNED; /* So far, never signed... */
#ifdef VBOX_PERMIT_VERIFIER_DLL
if (supHardViUtf16PathIsEqual(pwsz, "verifier.dll"))
return uNtVer < SUP_NT_VER_W81 ? VINF_LDRVI_NOT_SIGNED : rc;
@@ -919,7 +919,17 @@ static int supHardNtViCheckIfNotSignedOk(RTLDRMOD hLdrMod, PCRTUTF16 pwszName, u
/**
- * @callback_method_impl{RTCRPKCS7VERIFYCERTCALLBACK,
+ * @callback_method_impl{FNRTDUMPPRINTFV, Formats into RTERRINFO. }
+ */
+static DECLCALLBACK(void) supHardNtViAsn1DumpToErrInfo(void *pvUser, const char *pszFormat, va_list va)
+{
+ PRTERRINFO pErrInfo = (PRTERRINFO)pvUser;
+ RTErrInfoAddV(pErrInfo, pErrInfo->rc, pszFormat, va);
+}
+
+
+/**
+ * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
* Standard code signing. Use this for Microsoft SPC.}
*/
static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
@@ -937,7 +947,15 @@ static DECLCALLBACK(int) supHardNtViCertVerifyCallback(PCRTCRX509CERTIFICATE pCe
{
if (RTCrX509Certificate_Compare(pCert, &g_BuildX509Cert) == 0) /* healthy paranoia */
return VINF_SUCCESS;
- return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_BUILD_CERT_IPE, "Not valid kernel code signature.");
+ int rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_NOT_BUILD_CERT_IPE, "Not valid kernel code signature (fFlags=%#x).", fFlags);
+ if (pErrInfo)
+ {
+ RTErrInfoAdd(pErrInfo, rc, "\n\nExe cert:\n");
+ RTAsn1Dump(&pCert->SeqCore.Asn1Core, 0 /*fFlags*/, 0 /*uLevel*/, supHardNtViAsn1DumpToErrInfo, pErrInfo);
+ RTErrInfoAdd(pErrInfo, rc, "\n\nBuild cert:\n");
+ RTAsn1Dump(&g_BuildX509Cert.SeqCore.Asn1Core, 0 /*fFlags*/, 0 /*uLevel*/, supHardNtViAsn1DumpToErrInfo, pErrInfo);
+ }
+ return rc;
}
/*
@@ -1253,7 +1271,7 @@ DECLHIDDEN(int) supHardenedWinVerifyImageByHandle(HANDLE hFile, PCRTUTF16 pwszNa
supHardNtViRdrDestroy(&pNtViRdr->Core);
}
SUP_DPRINTF(("supHardenedWinVerifyImageByHandle: -> %d (%ls)%s\n",
- rc, pwszName, pfWinVerifyTrust && *pfWinVerifyTrust ? "WinVerifyTrust" : ""));
+ rc, pwszName, pfWinVerifyTrust && *pfWinVerifyTrust ? " WinVerifyTrust" : ""));
return rc;
}
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
index c0f8e6c..4605c33 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
@@ -213,7 +213,7 @@ typedef struct SUPR3WINPROCPARAMS
/** Where if message. */
char szWhere[80];
/** Error message / path name string space. */
- char szErrorMsg[4096];
+ char szErrorMsg[16384+1024];
} SUPR3WINPROCPARAMS;
@@ -790,7 +790,9 @@ DECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PC
if ( RTStrCmp(uBuf.szName, "kernel32.dll") == 0
|| RTStrCmp(uBuf.szName, "kernelbase.dll") == 0
|| RTStrCmp(uBuf.szName, "ntdll.dll") == 0
- || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("api-ms-win-")) == 0 )
+ || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("api-ms-win-")) == 0
+ || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("ext-ms-win-")) == 0
+ )
{
continue;
}
@@ -1708,8 +1710,11 @@ supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_S
* Not an absolute path. Check if it's one of those special API set DLLs
* or something we're known to use but should be taken from WinSxS.
*/
- else if (supHardViUtf16PathStartsWithEx(pName->Buffer, pName->Length / sizeof(WCHAR),
- L"api-ms-win-", 11, false /*fCheckSlash*/))
+ else if ( supHardViUtf16PathStartsWithEx(pName->Buffer, pName->Length / sizeof(WCHAR),
+ L"api-ms-win-", 11, false /*fCheckSlash*/)
+ || supHardViUtf16PathStartsWithEx(pName->Buffer, pName->Length / sizeof(WCHAR),
+ L"ext-ms-win-", 11, false /*fCheckSlash*/)
+ )
{
memcpy(wszPath, pName->Buffer, pName->Length);
wszPath[pName->Length / sizeof(WCHAR)] = '\0';
@@ -4169,17 +4174,18 @@ DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_
offRead.QuadPart = 0;
rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
&pszErrorInfo[cchPrefix], (ULONG)(cbErrorInfo - cchPrefix - 1), &offRead, NULL);
- if (NT_SUCCESS(rcNt))
+ if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status) && Ios.Information > 0)
{
memcpy(pszErrorInfo, pszPrefix, cchPrefix);
- pszErrorInfo[cbErrorInfo - 1] = '\0';
+ pszErrorInfo[RT_MIN(cbErrorInfo - 1, Ios.Information)] = '\0';
SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: '%s'", &pszErrorInfo[cchPrefix]));
}
else
{
*pszErrorInfo = '\0';
- if (rcNt != STATUS_END_OF_FILE)
- SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtReadFile -> %#x\n", rcNt));
+ if (rcNt != STATUS_END_OF_FILE || Ios.Status != STATUS_END_OF_FILE)
+ SUP_DPRINTF(("supR3HardenedWinReadErrorInfoDevice: NtReadFile -> %#x / %#x / %p\n",
+ rcNt, Ios.Status, Ios.Information));
}
}
else
@@ -4343,7 +4349,7 @@ static void supR3HardenedWinOpenStubDevice(void)
* extra information that goes into VBoxStartup.log so that we stand a
* better chance resolving the issue.
*/
- char szErrorInfo[_4K];
+ char szErrorInfo[16384];
int rc = VERR_OPEN_FAILED;
if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
{
@@ -4389,7 +4395,7 @@ static void supR3HardenedWinOpenStubDevice(void)
supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
"NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)%s", s_wszName, rc, rcNt,
supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
- "\nVBoxDrvStub error: "));
+ "\nVBoxDrvStub error: "));
}
else
{
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
index d6440e5..821df15 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm
@@ -163,6 +163,18 @@ BEGINPROC %1 %+ _SyscallType1
syscall
ret
ENDPROC %1 %+ _SyscallType1
+BEGINPROC %1 %+ _SyscallType2 ; Introduced with build 10525
+ SEH64_END_PROLOGUE
+ mov eax, [NAME(g_uApiNo %+ %1) xWrtRIP]
+ test byte [07ffe0308h], 1 ; SharedUserData!Something
+ mov r10, rcx
+ jnz .int_alternative
+ syscall
+ ret
+.int_alternative:
+ int 2eh
+ ret
+ENDPROC %1 %+ _SyscallType2
%else
BEGINPROC %1 %+ _SyscallType1
mov edx, 07ffe0300h ; SharedUserData!SystemCallStub
diff --git a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
index 99a1751..601ecc8 100644
--- a/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
@@ -91,9 +91,9 @@ typedef struct SUPHNTIMPSYSCALL
uint32_t *puApiNo;
/** Assembly system call routine, type 1. */
PFNRT pfnType1;
-#ifdef RT_ARCH_X86
/** Assembly system call routine, type 2. */
PFNRT pfnType2;
+#ifdef RT_ARCH_X86
/** The parameter size in bytes for a standard call. */
uint32_t cbParams;
#endif
@@ -214,7 +214,7 @@ static const SUPHNTIMPFUNC g_aSupNtImpKernel32Functions[] =
# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
{ NULL, NULL },
# define SUPHARNT_IMPORT_SYSCALL(a_Name, a_cbParamsX86) \
- { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name, _SyscallType1) },
+ { &RT_CONCAT(g_uApiNo, a_Name), &RT_CONCAT(a_Name, _SyscallType1), &RT_CONCAT(a_Name, _SyscallType2) },
#elif defined(RT_ARCH_X86)
# define SUPHARNT_IMPORT_STDCALL(a_Name, a_cbParamsX86) \
{ NULL, NULL, NULL, 0 },
@@ -449,14 +449,27 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
* Parse the code and extract the API call number.
*/
#ifdef RT_ARCH_AMD64
- /* Pattern #1: XP64/W2K3-64 thru Windows 8.1
- 0:000> u ntdll!NtCreateSection
- ntdll!NtCreateSection:
- 00000000`779f1750 4c8bd1 mov r10,rcx
- 00000000`779f1753 b847000000 mov eax,47h
- 00000000`779f1758 0f05 syscall
- 00000000`779f175a c3 ret
- 00000000`779f175b 0f1f440000 nop dword ptr [rax+rax] */
+ /* Pattern #1: XP64/W2K3-64 thru Windows 10 build 10240.
+ 0:000> u ntdll!NtCreateSection
+ ntdll!NtCreateSection:
+ 00000000`779f1750 4c8bd1 mov r10,rcx
+ 00000000`779f1753 b847000000 mov eax,47h
+ 00000000`779f1758 0f05 syscall
+ 00000000`779f175a c3 ret
+ 00000000`779f175b 0f1f440000 nop dword ptr [rax+rax]
+
+ Pattern #2: Windows 10 build 10525+.
+ 0:000> u ntdll_7ffc26300000!NtCreateSection
+ ntdll_7ffc26300000!ZwCreateSection:
+ 00007ffc`263943e0 4c8bd1 mov r10,rcx
+ 00007ffc`263943e3 b84a000000 mov eax,4Ah
+ 00007ffc`263943e8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
+ 00007ffc`263943f0 7503 jne ntdll_7ffc26300000!ZwCreateSection+0x15 (00007ffc`263943f5)
+ 00007ffc`263943f2 0f05 syscall
+ 00007ffc`263943f4 c3 ret
+ 00007ffc`263943f5 cd2e int 2Eh
+ 00007ffc`263943f7 c3 ret
+ */
if ( pbFunction[ 0] == 0x4c /* mov r10, rcx */
&& pbFunction[ 1] == 0x8b
&& pbFunction[ 2] == 0xd1
@@ -464,14 +477,37 @@ static void supR3HardenedDirectSyscall(PSUPHNTIMPDLL pDll, PCSUPHNTIMPFUNC pImpo
//&& pbFunction[ 4] == 0xZZ
//&& pbFunction[ 5] == 0xYY
&& pbFunction[ 6] == 0x00
- && pbFunction[ 7] == 0x00
- && pbFunction[ 8] == 0x0f /* syscall */
- && pbFunction[ 9] == 0x05
- && pbFunction[10] == 0xc3 /* ret */ )
+ && pbFunction[ 7] == 0x00)
{
- *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[4], pbFunction[5]);
- *pImport->ppfnImport = pSyscall->pfnType1;
- return;
+ if ( pbFunction[ 8] == 0x0f /* syscall */
+ && pbFunction[ 9] == 0x05
+ && pbFunction[10] == 0xc3 /* ret */ )
+ {
+ *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[4], pbFunction[5]);
+ *pImport->ppfnImport = pSyscall->pfnType1;
+ return;
+ }
+ if ( pbFunction[ 8] == 0xf6 /* test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 */
+ && pbFunction[ 9] == 0x04
+ && pbFunction[10] == 0x25
+ && pbFunction[11] == 0x08
+ && pbFunction[12] == 0x03
+ && pbFunction[13] == 0xfe
+ && pbFunction[14] == 0x7f
+ && pbFunction[15] == 0x01
+ && pbFunction[16] == 0x75 /* jnz +3 */
+ && pbFunction[17] == 0x03
+ && pbFunction[18] == 0x0f /* syscall*/
+ && pbFunction[19] == 0x05
+ && pbFunction[20] == 0xc3 /* ret */
+ && pbFunction[21] == 0xcd /* int 2eh */
+ && pbFunction[22] == 0x2e
+ && pbFunction[23] == 0xc3 /* ret */ )
+ {
+ *pSyscall->puApiNo = RT_MAKE_U16(pbFunction[4], pbFunction[5]);
+ *pImport->ppfnImport = pSyscall->pfnType2;
+ return;
+ }
}
#else
/* Pattern #1: XP thru Windows 7
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp b/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp
index e1a903b..07dd996 100644
--- a/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp
+++ b/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp
@@ -18,16 +18,9 @@
/*******************************************************************************
* 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
-
#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
+
#include <VBox/log.h>
#include <VBox/err.h>
#include <VBox/version.h>
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c b/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c
index 60833f8..0805dd4 100644
--- a/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c
+++ b/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c
@@ -423,7 +423,6 @@ static int __init VBoxNetAdpLinuxInit(void)
*/
static void __exit VBoxNetAdpLinuxUnload(void)
{
- int rc;
Log(("VBoxNetAdpLinuxUnload\n"));
/*
@@ -432,11 +431,7 @@ static void __exit VBoxNetAdpLinuxUnload(void)
vboxNetAdpShutdown();
/* Remove control device */
- rc = misc_deregister(&g_CtlDev);
- if (rc < 0)
- {
- printk(KERN_ERR "misc_deregister failed with rc=%x\n", rc);
- }
+ misc_deregister(&g_CtlDev);
RTR0Term();
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c b/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c
index 156f452..a74ec28 100644
--- a/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c
+++ b/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c
@@ -261,9 +261,11 @@ int _fini(void)
/*
* Undo the work done during start (in reverse order).
*/
- RTR0Term();
+ int rc = mod_remove(&g_VBoxNetAdpSolarisModLinkage);
+ if (!rc)
+ RTR0Term();
- return mod_remove(&g_VBoxNetAdpSolarisModLinkage);
+ return rc;
}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp b/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp
index ac17334..890d07d 100644
--- a/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp
+++ b/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetFlt-darwin.cpp
@@ -18,18 +18,9 @@
/*******************************************************************************
* 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 "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
+
#include <VBox/log.h>
#include <VBox/err.h>
#include <VBox/intnetinline.h>
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c b/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
index 30b46ba..13dd8d7 100644
--- a/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
+++ b/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c
@@ -23,6 +23,9 @@
#include "the-linux-kernel.h"
#include "version-generated.h"
#include "product-generated.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#include <linux/nsproxy.h>
+#endif
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
@@ -1804,7 +1807,7 @@ static int vboxNetFltLinuxDeviceMtuChange(PVBOXNETFLTINS pThis, struct net_devic
/** Stringify the NETDEV_XXX constants. */
static const char *vboxNetFltLinuxGetNetDevEventName(unsigned long ulEventType)
{
- const char *pszEvent = "NETDRV_<unknown>";
+ const char *pszEvent = "NETDEV_<unknown>";
switch (ulEventType)
{
case NETDEV_REGISTER: pszEvent = "NETDEV_REGISTER"; break;
@@ -1848,10 +1851,27 @@ static int vboxNetFltLinuxNotifierCallback(struct notifier_block *self, unsigned
Log(("VBoxNetFlt: got event %s(0x%lx) on %s, pDev=%p pThis=%p pThis->u.s.pDev=%p\n",
vboxNetFltLinuxGetNetDevEventName(ulEventType), ulEventType, pDev->name, pDev, pThis, pMyDev));
- if ( ulEventType == NETDEV_REGISTER
- && !strcmp(pDev->name, pThis->szName))
+ if (ulEventType == NETDEV_REGISTER)
{
- vboxNetFltLinuxAttachToInterface(pThis, pDev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) /* cgroups/namespaces introduced */
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+# define VBOX_DEV_NET(dev) dev_net(dev)
+# define VBOX_NET_EQ(n1, n2) net_eq((n1), (n2))
+# else
+# define VBOX_DEV_NET(dev) ((dev)->nd_net)
+# define VBOX_NET_EQ(n1, n2) ((n1) == (n2))
+# endif
+ struct net *pMyNet = current->nsproxy->net_ns;
+ struct net *pDevNet = VBOX_DEV_NET(pDev);
+
+ if (VBOX_NET_EQ(pDevNet, pMyNet))
+#endif /* namespaces */
+ {
+ if (strcmp(pDev->name, pThis->szName) == 0)
+ {
+ vboxNetFltLinuxAttachToInterface(pThis, pDev);
+ }
+ }
}
else
{
@@ -2059,6 +2079,7 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, u
struct net_device * pDev;
int err;
int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
NOREF(pvIfData);
LogFlow(("vboxNetFltPortOsXmit: pThis=%p (%s)\n", pThis, pThis->szName));
@@ -2107,17 +2128,18 @@ int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, u
vboxNetFltLinuxReleaseNetDev(pThis, pDev);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
{
- struct net_device * pDev;
+ struct net_device *pDev;
+ IPRT_LINUX_SAVE_EFL_AC();
- LogFlow(("vboxNetFltPortOsSetActive: pThis=%p (%s), fActive=%s, fDisablePromiscuous=%s\n",
- pThis, pThis->szName, fActive?"true":"false",
- pThis->fDisablePromiscuous?"true":"false"));
+ LogFlow(("vboxNetFltPortOsSetActive: pThis=%p (%s), fActive=%RTbool, fDisablePromiscuous=%RTbool\n",
+ pThis, pThis->szName, fActive, pThis->fDisablePromiscuous));
if (pThis->fDisablePromiscuous)
return;
@@ -2164,6 +2186,7 @@ void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
vboxNetFltLinuxReleaseNetDev(pThis, pDev);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
}
@@ -2175,8 +2198,10 @@ int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
*/
if (ASMAtomicCmpXchgBool(&pThis->u.s.fPacketHandler, false, true))
{
+ IPRT_LINUX_SAVE_EFL_AC();
dev_remove_pack(&pThis->u.s.PacketType);
Log(("vboxNetFltOsDisconnectIt: this=%p: Packet handler removed.\n", pThis));
+ IPRT_LINUX_RESTORE_EFL_AC();
}
return VINF_SUCCESS;
}
@@ -2184,6 +2209,8 @@ int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Report the GSO capabilities of the host and device (if connected).
* Note! No need to mark ourselves busy here.
@@ -2204,6 +2231,7 @@ int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
#endif
vboxNetFltLinuxReportNicGsoCapabilities(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -2212,6 +2240,7 @@ void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
{
struct net_device *pDev;
bool fRegistered;
+ IPRT_LINUX_SAVE_EFL_AC();
#ifdef VBOXNETFLT_WITH_HOST2WIRE_FILTER
vboxNetFltLinuxUnhookDev(pThis, NULL);
@@ -2252,6 +2281,8 @@ void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
Log(("vboxNetFltOsDeleteInstance: this=%p: Notifier removed.\n", pThis));
unregister_netdevice_notifier(&pThis->u.s.Notifier);
module_put(THIS_MODULE);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
}
@@ -2259,22 +2290,30 @@ int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
{
int err;
NOREF(pvContext);
+ IPRT_LINUX_SAVE_EFL_AC();
pThis->u.s.Notifier.notifier_call = vboxNetFltLinuxNotifierCallback;
err = register_netdevice_notifier(&pThis->u.s.Notifier);
if (err)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
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));
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_INTNET_FLT_IF_NOT_FOUND;
}
Log(("vboxNetFltOsInitInstance: this=%p: Notifier installed.\n", pThis));
if ( pThis->fDisconnectedFromHost
|| !try_module_get(THIS_MODULE))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_INTNET_FLT_IF_FAILED;
+ }
if (pThis->pSwitchPort->pfnNotifyHostAddress)
{
@@ -2293,8 +2332,8 @@ int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
err = register_netdevice_notifier(&Enumerator.Notifier);
if (err)
{
- LogRel(("%s: failed to enumerate network devices: error %d\n",
- __FUNCTION__, err));
+ LogRel(("%s: failed to enumerate network devices: error %d\n", __FUNCTION__, err));
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -2303,21 +2342,22 @@ int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
pThis->u.s.NotifierIPv4.notifier_call = vboxNetFltLinuxNotifierIPv4Callback;
err = register_inetaddr_notifier(&pThis->u.s.NotifierIPv4);
if (err)
- LogRel(("%s: failed to register IPv4 notifier: error %d\n",
- __FUNCTION__, err));
+ LogRel(("%s: failed to register IPv4 notifier: error %d\n", __FUNCTION__, err));
pThis->u.s.NotifierIPv6.notifier_call = vboxNetFltLinuxNotifierIPv6Callback;
err = register_inet6addr_notifier(&pThis->u.s.NotifierIPv6);
if (err)
- LogRel(("%s: failed to register IPv6 notifier: error %d\n",
- __FUNCTION__, err));
+ LogRel(("%s: failed to register IPv6 notifier: error %d\n", __FUNCTION__, err));
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Init the linux specific members.
*/
@@ -2335,6 +2375,7 @@ int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
# endif
#endif
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
diff --git a/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c b/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c
index f8e3f46..37c4767 100644
--- a/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c
+++ b/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c
@@ -136,7 +136,9 @@ static int __init VBoxPciLinuxInit(void)
{
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
/* find_module() is static before Linux 2.6.30 */
+ mutex_lock(&module_mutex);
g_VBoxPciGlobals.pciStubModule = find_module(PCI_STUB_MODULE_NAME);
+ mutex_unlock(&module_mutex);
if (g_VBoxPciGlobals.pciStubModule)
{
if (try_module_get(g_VBoxPciGlobals.pciStubModule))
diff --git a/src/VBox/HostServices/GuestProperties/service.cpp b/src/VBox/HostServices/GuestProperties/service.cpp
index bd3a162..a25825c 100644
--- a/src/VBox/HostServices/GuestProperties/service.cpp
+++ b/src/VBox/HostServices/GuestProperties/service.cpp
@@ -57,6 +57,9 @@
#include <string>
#include <list>
+/** @todo Delete the old !ASYNC_HOST_NOTIFY code and remove this define. */
+#define ASYNC_HOST_NOTIFY
+
namespace guestProp {
/**
@@ -285,6 +288,10 @@ public:
, mpvHostData(NULL)
, mPrevTimestamp(0)
, mcTimestampAdjustments(0)
+#ifdef ASYNC_HOST_NOTIFY
+ , mhThreadNotifyHost(NIL_RTTHREAD)
+ , mhReqQNotifyHost(NIL_RTREQQUEUE)
+#endif
{ }
/**
@@ -364,6 +371,10 @@ public:
return VINF_SUCCESS;
}
+#ifdef ASYNC_HOST_NOTIFY
+ int initialize();
+#endif
+
private:
static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
uint64_t getCurrentTimestamp(void);
@@ -390,6 +401,14 @@ private:
int uninit();
void dbgInfoShow(PCDBGFINFOHLP pHlp);
static DECLCALLBACK(void) dbgInfo(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs);
+
+#ifdef ASYNC_HOST_NOTIFY
+ /* Thread for handling host notifications. */
+ RTTHREAD mhThreadNotifyHost;
+ /* Queue for handling requests for notifications. */
+ RTREQQUEUE mhReqQNotifyHost;
+ static DECLCALLBACK(int) threadNotifyHost(RTTHREAD self, void *pvUser);
+#endif
};
@@ -1206,6 +1225,18 @@ int Service::doNotifications(const char *pszProperty, uint64_t u64Timestamp)
return rc;
}
+#ifdef ASYNC_HOST_NOTIFY
+static DECLCALLBACK(void) notifyHostAsyncWorker(PFNHGCMSVCEXT pfnHostCallback,
+ void *pvHostData,
+ HOSTCALLBACKDATA *pHostCallbackData)
+{
+ pfnHostCallback(pvHostData, 0 /*u32Function*/,
+ (void *)pHostCallbackData,
+ sizeof(HOSTCALLBACKDATA));
+ RTMemFree(pHostCallbackData);
+}
+#endif
+
/**
* Notify the service owner that a property has been added/deleted/changed.
* @returns IPRT status value
@@ -1219,6 +1250,52 @@ int Service::notifyHost(const char *pszName, const char *pszValue,
{
LogFlowFunc(("pszName=%s, pszValue=%s, u64Timestamp=%llu, pszFlags=%s\n",
pszName, pszValue, u64Timestamp, pszFlags));
+#ifdef ASYNC_HOST_NOTIFY
+ int rc = VINF_SUCCESS;
+
+ /* Allocate buffer for the callback data and strings. */
+ size_t cbName = pszName? strlen(pszName): 0;
+ size_t cbValue = pszValue? strlen(pszValue): 0;
+ size_t cbFlags = pszFlags? strlen(pszFlags): 0;
+ size_t cbAlloc = sizeof(HOSTCALLBACKDATA) + cbName + cbValue + cbFlags + 3;
+ HOSTCALLBACKDATA *pHostCallbackData = (HOSTCALLBACKDATA *)RTMemAlloc(cbAlloc);
+ if (pHostCallbackData)
+ {
+ uint8_t *pu8 = (uint8_t *)pHostCallbackData;
+ pu8 += sizeof(HOSTCALLBACKDATA);
+
+ pHostCallbackData->u32Magic = HOSTCALLBACKMAGIC;
+
+ pHostCallbackData->pcszName = (const char *)pu8;
+ memcpy(pu8, pszName, cbName);
+ pu8 += cbName;
+ *pu8++ = 0;
+
+ pHostCallbackData->pcszValue = (const char *)pu8;
+ memcpy(pu8, pszValue, cbValue);
+ pu8 += cbValue;
+ *pu8++ = 0;
+
+ pHostCallbackData->u64Timestamp = u64Timestamp;
+
+ pHostCallbackData->pcszFlags = (const char *)pu8;
+ memcpy(pu8, pszFlags, cbFlags);
+ pu8 += cbFlags;
+ *pu8++ = 0;
+
+ rc = RTReqQueueCallEx(mhReqQNotifyHost, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
+ (PFNRT)notifyHostAsyncWorker, 3,
+ mpfnHostCallback, mpvHostData, pHostCallbackData);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(pHostCallbackData);
+ }
+ }
+ else
+ {
+ rc = VERR_NO_MEMORY;
+ }
+#else
HOSTCALLBACKDATA HostCallbackData;
HostCallbackData.u32Magic = HOSTCALLBACKMAGIC;
HostCallbackData.pcszName = pszName;
@@ -1228,6 +1305,7 @@ int Service::notifyHost(const char *pszName, const char *pszValue,
int rc = mpfnHostCallback(mpvHostData, 0 /*u32Function*/,
(void *)(&HostCallbackData),
sizeof(HostCallbackData));
+#endif
LogFlowFunc(("returning rc=%Rrc\n", rc));
return rc;
}
@@ -1438,8 +1516,84 @@ int Service::hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paPa
return rc;
}
+#ifdef ASYNC_HOST_NOTIFY
+/* static */
+DECLCALLBACK(int) Service::threadNotifyHost(RTTHREAD self, void *pvUser)
+{
+ Service *pThis = (Service *)pvUser;
+ int rc = VINF_SUCCESS;
+
+ LogFlowFunc(("ENTER: %p\n", pThis));
+
+ for (;;)
+ {
+ rc = RTReqQueueProcess(pThis->mhReqQNotifyHost, RT_INDEFINITE_WAIT);
+
+ AssertMsg(rc == VWRN_STATE_CHANGED,
+ ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n",
+ rc));
+ if (rc == VWRN_STATE_CHANGED)
+ {
+ break;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: %Rrc\n", rc));
+ return rc;
+}
+
+static DECLCALLBACK(int) wakeupNotifyHost(void)
+{
+ /* Returning a VWRN_* will cause RTReqQueueProcess return. */
+ return VWRN_STATE_CHANGED;
+}
+
+int Service::initialize()
+{
+ /* The host notification thread and queue. */
+ int rc = RTReqQueueCreate(&mhReqQNotifyHost);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreate(&mhThreadNotifyHost,
+ threadNotifyHost,
+ this,
+ 0 /* default stack size */,
+ RTTHREADTYPE_DEFAULT,
+ 0, /* no flags. */
+ "GSTPROPNTFY");
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ if (mhReqQNotifyHost != NIL_RTREQQUEUE)
+ {
+ RTReqQueueDestroy(mhReqQNotifyHost);
+ mhReqQNotifyHost = NIL_RTREQQUEUE;
+ }
+ }
+
+ return rc;
+}
+#endif
+
int Service::uninit()
{
+#ifdef ASYNC_HOST_NOTIFY
+ if (mhReqQNotifyHost != NIL_RTREQQUEUE)
+ {
+ /* Stop the thread */
+ PRTREQ pReq;
+ int rc = RTReqQueueCall(mhReqQNotifyHost, &pReq, 10000, (PFNRT)wakeupNotifyHost, 0);
+ if (RT_SUCCESS(rc))
+ RTReqRelease(pReq);
+
+ rc = RTReqQueueDestroy(mhReqQNotifyHost);
+ AssertRC(rc);
+ mhReqQNotifyHost = NIL_RTREQQUEUE;
+ mhThreadNotifyHost = NIL_RTTHREAD;
+ }
+#endif
+
return VINF_SUCCESS;
}
@@ -1499,6 +1653,15 @@ extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *pt
/* Service specific initialization. */
ptable->pvService = pService;
+
+#ifdef ASYNC_HOST_NOTIFY
+ rc = pService->initialize();
+ if (RT_FAILURE(rc))
+ {
+ delete pService;
+ pService = NULL;
+ }
+#endif
}
else
Assert(!pService);
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py
old mode 100755
new mode 100644
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py
old mode 100755
new mode 100644
diff --git a/src/VBox/Installer/linux/rpm/rules b/src/VBox/Installer/linux/rpm/rules
index 8bfd4ff..7cbe336 100755
--- a/src/VBox/Installer/linux/rpm/rules
+++ b/src/VBox/Installer/linux/rpm/rules
@@ -87,7 +87,7 @@ ifneq ($(MAKECMDGOALS),clean)
ifeq ($(filter-out el5 el6 ol5 ol6 el7 centos5 centos6 fedora17 fedora18 fedora19 fedora20 fedora21 fedora22,$(rpmrel)),)
rpmspec := rpm_redhat
endif
- ifeq ($(filter-out openSUSE110 openSUSE111 openSUSE112 openSUSE113 openSUSE114 openSUSE123 openSUSE131 openSUSE132 sles10.1 sles11.0,$(rpmrel)),)
+ ifeq ($(filter-out openSUSE110 openSUSE111 openSUSE112 openSUSE113 openSUSE114 openSUSE123 sles10.1 sles11.0,$(rpmrel)),)
rpmspec := rpm_suse
endif
ifeq ($(filter-out mdv2009.1 mdv2010.0 mdv2011.0,$(rpmrel)),)
diff --git a/src/VBox/Installer/linux/vboxdrv.sh.in b/src/VBox/Installer/linux/vboxdrv.sh.in
index 82bbdbf..ae9acfa 100755
--- a/src/VBox/Installer/linux/vboxdrv.sh.in
+++ b/src/VBox/Installer/linux/vboxdrv.sh.in
@@ -172,11 +172,11 @@ start()
fi
# ensure the character special exists
if [ ! -c $DEVICE ]; then
- MAJOR=`sed -n 's;\([0-9]\+\) vboxdrv;\1;p' /proc/devices`
+ MAJOR=`sed -n 's;\([0-9]\+\) vboxdrv$;\1;p' /proc/devices`
if [ ! -z "$MAJOR" ]; then
MINOR=0
else
- MINOR=`sed -n 's;\([0-9]\+\) vboxdrv;\1;p' /proc/misc`
+ MINOR=`sed -n 's;\([0-9]\+\) vboxdrv$;\1;p' /proc/misc`
if [ ! -z "$MINOR" ]; then
MAJOR=10
fi
diff --git a/src/VBox/Main/glue/constants-python.xsl b/src/VBox/Main/glue/constants-python.xsl
old mode 100644
new mode 100755
diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl
index 272d3ae..aebdae6 100644
--- a/src/VBox/Main/idl/VirtualBox.xidl
+++ b/src/VBox/Main/idl/VirtualBox.xidl
@@ -3415,7 +3415,7 @@
<interface
name="IInternalMachineControl" extends="$unknown"
- uuid="2d9ce4b7-0ab2-4931-ac4a-e45aa66465ef"
+ uuid="906283f2-d59e-4223-95a6-7675663e1b6d"
internal="yes"
wsmap="suppress"
>
@@ -3811,6 +3811,11 @@
The flags of the property.
</desc>
</param>
+ <param name="notify" type="boolean" dir="return">
+ <desc>
+ Returns if a guest property change notification event should be fired.
+ </desc>
+ </param>
</method>
<method name="lockMedia">
diff --git a/src/VBox/Main/include/ConsoleImpl.h b/src/VBox/Main/include/ConsoleImpl.h
index 46217f1..ecdd568 100644
--- a/src/VBox/Main/include/ConsoleImpl.h
+++ b/src/VBox/Main/include/ConsoleImpl.h
@@ -192,6 +192,7 @@ public:
AudioSniffer *getAudioSniffer() const { return mAudioSniffer; }
const ComPtr<IMachine> &machine() const { return mMachine; }
+ const Bstr &getId() const { return mstrUuid; }
bool useHostClipboard() { return mfUseHostClipboard; }
@@ -957,6 +958,9 @@ private:
/** Local machine state value. */
MachineState_T mMachineState;
+ /** Machine uuid string. */
+ Bstr mstrUuid;
+
/** Pointer to the progress object of a live cancelable task.
*
* This is currently only used by Console::Teleport(), but is intended to later
diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h
index d3c6d85..52d1d17 100644
--- a/src/VBox/Main/include/MachineImpl.h
+++ b/src/VBox/Main/include/MachineImpl.h
@@ -756,7 +756,7 @@ public:
void getLogFolder(Utf8Str &aLogFolder);
Utf8Str queryLogFilename(ULONG idx);
- Utf8Str i_getStartupLogFilename(void);
+ Utf8Str i_getHardeningLogFilename(void);
void composeSavedStateFilename(Utf8Str &strStateFilePath);
@@ -1085,7 +1085,8 @@ public:
STDMETHOD(PullGuestProperties)(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(BSTR, aValues),
ComSafeArrayOut(LONG64, aTimestamps), ComSafeArrayOut(BSTR, aFlags));
STDMETHOD(PushGuestProperty)(IN_BSTR aName, IN_BSTR aValue,
- LONG64 aTimestamp, IN_BSTR aFlags);
+ LONG64 aTimestamp, IN_BSTR aFlags,
+ BOOL *aNotify);
STDMETHOD(LockMedia)();
STDMETHOD(UnlockMedia)();
STDMETHOD(EjectMedium)(IMediumAttachment *aAttachment,
diff --git a/src/VBox/Main/src-client/ConsoleImpl.cpp b/src/VBox/Main/src-client/ConsoleImpl.cpp
index c87efbf..c6044d6 100644
--- a/src/VBox/Main/src-client/ConsoleImpl.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl.cpp
@@ -302,7 +302,7 @@ public:
{
}
- STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent * aEvent)
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
{
switch(aType)
{
@@ -314,12 +314,9 @@ public:
HRESULT rc = E_FAIL;
Assert(pNREv);
- Bstr interestedId;
- rc = pMachine->COMGETTER(Id)(interestedId.asOutParam());
- AssertComRC(rc);
rc = pNREv->COMGETTER(MachineId)(id.asOutParam());
AssertComRC(rc);
- if (id != interestedId)
+ if (id != mConsole->getId())
break;
/* now we can operate with redirects */
NATProtocol_T proto;
@@ -378,6 +375,7 @@ public:
default:
AssertFailed();
}
+
return S_OK;
}
private:
@@ -506,6 +504,9 @@ HRESULT Console::init(IMachine *aMachine, IInternalMachineControl *aControl, Loc
rc = mMachine->COMGETTER(State)(&mMachineState);
AssertComRCReturnRC(rc);
+ rc = mMachine->COMGETTER(Id)(mstrUuid.asOutParam());
+ AssertComRCReturnRC(rc);
+
#ifdef VBOX_WITH_EXTPACK
unconst(mptrExtPackManager).createObject();
rc = mptrExtPackManager->initExtPackManager(NULL, VBOXEXTPACKCTX_VM_PROCESS);
@@ -1094,14 +1095,10 @@ int Console::VRDPClientLogon(uint32_t u32ClientId, const char *pszUser, const ch
return VERR_ACCESS_DENIED;
}
- Bstr id;
- HRESULT hrc = mMachine->COMGETTER(Id)(id.asOutParam());
- Guid uuid = Guid(id);
-
- AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
+ Guid uuid = Guid(getId());
AuthType_T authType = AuthType_Null;
- hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
+ HRESULT hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
ULONG authTimeout = 0;
@@ -1443,16 +1440,12 @@ void Console::VRDPClientDisconnect(uint32_t u32ClientId,
}
}
- Bstr uuid;
- HRESULT hrc = mMachine->COMGETTER(Id)(uuid.asOutParam());
- AssertComRC(hrc);
-
AuthType_T authType = AuthType_Null;
- hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
+ HRESULT hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
AssertComRC(hrc);
if (authType == AuthType_External)
- mConsoleVRDPServer->AuthDisconnect(uuid, u32ClientId);
+ mConsoleVRDPServer->AuthDisconnect(getId(), u32ClientId);
#ifdef VBOX_WITH_GUEST_PROPS
guestPropertiesVRDPUpdateDisconnect(u32ClientId);
@@ -1787,10 +1780,12 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension,
Bstr value(pCBData->pcszValue);
Bstr flags(pCBData->pcszFlags);
ComObjPtr<Console> pConsole = reinterpret_cast<Console *>(pvExtension);
+ BOOL fNotify = FALSE;
HRESULT hrc = pConsole->mControl->PushGuestProperty(name.raw(),
value.raw(),
pCBData->u64Timestamp,
- flags.raw());
+ flags.raw(),
+ &fNotify);
if (SUCCEEDED(hrc))
rc = VINF_SUCCESS;
else
@@ -1799,6 +1794,8 @@ DECLCALLBACK(int) Console::doGuestPropNotification(void *pvExtension,
hrc, pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
rc = Global::vboxStatusCodeFromCOM(hrc);
}
+ if (fNotify)
+ fireGuestPropertyChangedEvent(pConsole->mEventSource, pConsole->getId().raw(), name.raw(), value.raw(), flags.raw());
return rc;
}
@@ -2440,7 +2437,7 @@ HRESULT Console::doCPURemove(ULONG aCpu, PUVM pUVM)
vrc = VMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
(PFNRT)unplugCpu, 3,
this, pUVM, (VMCPUID)aCpu);
-
+
/* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
alock.release();
@@ -3548,7 +3545,7 @@ HRESULT Console::convertBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG
// private methods
/////////////////////////////////////////////////////////////////////////////
-
+
/**
* Suspend the VM before we do any medium or network attachment change.
*
@@ -5753,10 +5750,8 @@ HRESULT Console::onExtraDataChange(IN_BSTR aMachineId, IN_BSTR aKey, IN_BSTR aVa
HRESULT hrc = S_OK;
Bstr idMachine(aMachineId);
- Bstr idSelf;
- hrc = mMachine->COMGETTER(Id)(idSelf.asOutParam());
if ( FAILED(hrc)
- || idMachine != idSelf)
+ || idMachine != getId())
return hrc;
/* don't do anything if the VM isn't running */
@@ -7188,7 +7183,7 @@ HRESULT Console::powerUp(IProgress **aProgress, bool aPaused)
throw rc;
}
- if (!fCurrentSnapshotIsOnline)
+ if (savedStateFile.isEmpty() && !fCurrentSnapshotIsOnline)
{
LogFlowThisFunc(("Looking for immutable images to reset\n"));
diff --git a/src/VBox/Main/src-client/DisplayImpl.cpp b/src/VBox/Main/src-client/DisplayImpl.cpp
index 2aa362a..7221716 100644
--- a/src/VBox/Main/src-client/DisplayImpl.cpp
+++ b/src/VBox/Main/src-client/DisplayImpl.cpp
@@ -3646,11 +3646,9 @@ STDMETHODIMP Display::ViewportChanged(ULONG aScreenId, ULONG x, ULONG y, ULONG w
}
#endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */
-#ifdef VBOX_WITH_VMSVGA
/* The driver might not have been constructed yet */
- if (mpDrv)
- mpDrv->pUpPort->pfnSetViewPort(mpDrv->pUpPort, aScreenId, x, y, width, height);
-#endif
+ if (mpDrv && mpDrv->pUpPort->pfnSetViewport)
+ mpDrv->pUpPort->pfnSetViewport(mpDrv->pUpPort, aScreenId, x, y, width, height);
return S_OK;
}
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp
index a814909..138cb11 100644
--- a/src/VBox/Main/src-server/ApplianceImplExport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp
@@ -1821,7 +1821,8 @@ void Appliance::buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
pelmVBoxMachine->createChild("ovf:Info")->addContent("Complete VirtualBox machine configuration in VirtualBox format");
// create an empty machine config
- settings::MachineConfigFile *pConfig = new settings::MachineConfigFile(NULL);
+ // use the same settings version as the current VM settings file
+ settings::MachineConfigFile *pConfig = new settings::MachineConfigFile(&vsdescThis->m->pMachine->getSettingsFileFull());
writeLock.release();
try
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index cc9c44d..73a984f 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -5804,8 +5804,9 @@ HRESULT Machine::deleteTaskWorker(DeleteTask &task)
RTFileDelete(log.c_str());
}
#if defined(RT_OS_WINDOWS)
- log = Utf8StrFmt("%s%cVBoxStartup.log",
- logFolder.c_str(), RTPATH_DELIMITER);
+ log = Utf8StrFmt("%s%cVBoxStartup.log", logFolder.c_str(), RTPATH_DELIMITER);
+ RTFileDelete(log.c_str());
+ log = Utf8StrFmt("%s%cVBoxHardening.log", logFolder.c_str(), RTPATH_DELIMITER);
RTFileDelete(log.c_str());
#endif
@@ -7915,14 +7916,14 @@ Utf8Str Machine::queryLogFilename(ULONG idx)
}
/**
- * Returns the full path to the machine's (hardened) startup log file.
+ * Returns the full path to the machine's hardened log file.
*/
-Utf8Str Machine::i_getStartupLogFilename(void)
+Utf8Str Machine::i_getHardeningLogFilename(void)
{
Utf8Str strFilename;
getLogFolder(strFilename);
Assert(strFilename.length());
- strFilename.append(RTPATH_SLASH_STR "VBoxStartup.log");
+ strFilename.append(RTPATH_SLASH_STR "VBoxHardening.log");
return strFilename;
}
@@ -8093,23 +8094,29 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
RTStrFree(newEnvStr);
}
- /* Hardened startup logging */
+ /* Hardening logging */
#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_HARDENING)
- Utf8Str strSupStartLogArg("--sup-startup-log=");
+ Utf8Str strSupHardeningLogArg("--sup-hardening-log=");
{
- Utf8Str strStartupLogFile = i_getStartupLogFilename();
- int vrc2 = RTFileDelete(strStartupLogFile.c_str());
+ Utf8Str strHardeningLogFile = i_getHardeningLogFilename();
+ int vrc2 = RTFileDelete(strHardeningLogFile.c_str());
if (vrc2 == VERR_PATH_NOT_FOUND || vrc2 == VERR_FILE_NOT_FOUND)
{
- Utf8Str strStartupLogDir = strStartupLogFile;
+ Utf8Str strStartupLogDir = strHardeningLogFile;
strStartupLogDir.stripFilename();
RTDirCreateFullPath(strStartupLogDir.c_str(), 0755); /** @todo add a variant for creating the path to a file without stripping the file. */
}
- strSupStartLogArg.append(strStartupLogFile);
+ strSupHardeningLogArg.append(strHardeningLogFile);
+
+ /* Remove legacy log filename to avoid confusion. */
+ Utf8Str strOldStartupLogFile;
+ getLogFolder(strOldStartupLogFile);
+ strOldStartupLogFile.append(RTPATH_SLASH_STR "VBoxStartup.log");
+ RTFileDelete(strOldStartupLogFile.c_str());
}
- const char *pszSupStartupLogArg = strSupStartLogArg.c_str();
+ const char *pszSupHardeningLogArg = strSupHardeningLogArg.c_str();
#else
- const char *pszSupStartupLogArg = NULL;
+ const char *pszSupHardeningLogArg = NULL;
#endif
@@ -8160,7 +8167,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
"--comment", mUserData->s.strName.c_str(),
"--startvm", idStr.c_str(),
"--no-startvm-errormsgbox",
- pszSupStartupLogArg,
+ pszSupHardeningLogArg,
NULL
};
vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
@@ -8185,7 +8192,7 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
szPath,
"--comment", mUserData->s.strName.c_str(),
"--startvm", idStr.c_str(),
- pszSupStartupLogArg,
+ pszSupHardeningLogArg,
NULL
};
vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
@@ -8222,13 +8229,13 @@ HRESULT Machine::launchVMProcess(IInternalSessionControl *aControl,
"--startvm", idStr.c_str(),
"--vrde", "config",
0, /* For "--capture". */
- 0, /* For "--sup-startup-log". */
+ 0, /* For "--sup-hardening-log". */
0
};
unsigned iArg = 7;
if (strFrontend == "capture")
apszArgs[iArg++] = "--capture";
- apszArgs[iArg++] = pszSupStartupLogArg;
+ apszArgs[iArg++] = pszSupHardeningLogArg;
# ifdef RT_OS_WINDOWS
vrc = RTProcCreate(szPath, apszArgs, env, RTPROC_FLAGS_NO_WINDOW, &pid);
@@ -8417,11 +8424,11 @@ bool Machine::checkForSpawnFailure()
/* If the startup logfile exists and is of non-zero length, tell the
user to look there for more details to encourage them to attach it
when reporting startup issues. */
- Utf8Str strStartupLogFile = i_getStartupLogFilename();
+ Utf8Str strHardeningLogFile = i_getHardeningLogFilename();
uint64_t cbStartupLogFile = 0;
- int vrc2 = RTFileQuerySize(strStartupLogFile.c_str(), &cbStartupLogFile);
+ int vrc2 = RTFileQuerySize(strHardeningLogFile.c_str(), &cbStartupLogFile);
if (RT_SUCCESS(vrc2) && cbStartupLogFile > 0)
- strExtraInfo.append(Utf8StrFmt(tr(". More details may be available in '%s'"), strStartupLogFile.c_str()));
+ strExtraInfo.append(Utf8StrFmt(tr(". More details may be available in '%s'"), strHardeningLogFile.c_str()));
#endif
if (RT_SUCCESS(vrc) && status.enmReason == RTPROCEXITREASON_NORMAL)
@@ -13893,7 +13900,8 @@ STDMETHODIMP SessionMachine::PullGuestProperties(ComSafeArrayOut(BSTR, aNames),
STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
IN_BSTR aValue,
LONG64 aTimestamp,
- IN_BSTR aFlags)
+ IN_BSTR aFlags,
+ BOOL *aNotify)
{
LogFlowThisFunc(("\n"));
@@ -13904,6 +13912,8 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
CheckComArgNotNull(aValue);
CheckComArgNotNull(aFlags);
+ *aNotify = FALSE;
+
try
{
/*
@@ -13989,6 +13999,7 @@ STDMETHODIMP SessionMachine::PushGuestProperty(IN_BSTR aName,
aName,
aValue,
aFlags);
+ *aNotify = TRUE;
}
}
catch (...)
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk
index 607c00b..ed23226 100644
--- a/src/VBox/Runtime/Makefile.kmk
+++ b/src/VBox/Runtime/Makefile.kmk
@@ -359,7 +359,10 @@ RuntimeR3_SOURCES = \
common/crypto/tsp-sanity.cpp \
common/crypto/store.cpp \
common/crypto/store-inmem.cpp \
- common/crypto/RTCrStoreCertAddFromFile.cpp \
+ common/crypto/store-cert-add-basic.cpp \
+ common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp \
+ common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp \
+ common/crypto/RTCrStoreCertExportAsPem.cpp \
common/dbg/dbg.cpp \
common/dbg/dbgas.cpp \
common/dbg/dbgcfg.cpp \
@@ -449,8 +452,10 @@ RuntimeR3_SOURCES = \
common/path/RTPathChangeToUnixSlashes.cpp \
common/path/RTPathCopyComponents.cpp \
common/path/RTPathCountComponents.cpp \
+ common/path/RTPathEnsureTrailingSeparator.cpp \
common/path/RTPathExt.cpp \
common/path/RTPathFilename.cpp \
+ common/path/RTPathGlob.cpp \
common/path/RTPathHasExt.cpp \
common/path/RTPathHasPath.cpp \
common/path/RTPathJoin.cpp \
@@ -713,6 +718,7 @@ RuntimeR3_SOURCES.win = \
r3/nt/pathint-nt.cpp \
r3/nt/RTProcQueryParent-r3-nt.cpp \
r3/win/env-win.cpp \
+ r3/win/RTCrStoreCreateSnapshotById-win.cpp \
r3/win/RTHandleGetStandard-win.cpp \
r3/win/RTSystemQueryOSInfo-win.cpp \
r3/win/RTSystemShutdown-win.cpp \
@@ -752,11 +758,16 @@ RuntimeR3_SOURCES.win = \
win/RTErrConvertFromWin32.cpp \
common/string/mempcpy.asm
-RuntimeR3_SOURCES.win.amd64 := $(RuntimeWin64ASM_SOURCES)
-RuntimeR3_SOURCES.win.x86 := $(RuntimeWin32ASM_SOURCES)
+RuntimeR3_SOURCES.win.amd64 := \
+ $(RuntimeWin64ASM_SOURCES) \
+ common/string/memrchr.asm
+RuntimeR3_SOURCES.win.x86 := \
+ $(RuntimeWin32ASM_SOURCES) \
+ common/string/memrchr.asm
RuntimeR3_SOURCES.linux = \
generic/cdrom-generic.cpp \
+ generic/RTCrStoreCreateSnapshotById-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
@@ -843,7 +854,9 @@ else
endif
RuntimeR3_SOURCES.os2 = \
+ common/string/memrchr.asm \
generic/cdrom-generic.cpp \
+ generic/RTCrStoreCreateSnapshotById-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
@@ -942,6 +955,7 @@ RuntimeR3_SOURCES.darwin = \
generic/uuid-generic.cpp\
generic/RTProcIsRunningByName-generic.cpp \
generic/RTThreadGetNativeState-generic.cpp \
+ r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp \
r3/darwin/filelock-darwin.cpp \
r3/darwin/mp-darwin.cpp \
r3/darwin/pathhost-darwin.cpp \
@@ -984,10 +998,13 @@ RuntimeR3_SOURCES.darwin = \
r3/posix/timelocal-posix.cpp \
r3/posix/tls-posix.cpp \
r3/posix/utf8-posix.cpp
+RuntimeR3_SOURCES.darwin.x86 += common/string/memrchr.asm
+RuntimeR3_SOURCES.darwin.amd64 += common/string/memrchr.asm
## @todo Make BSD sched, implement RTMP*.
RuntimeR3_SOURCES.freebsd = \
generic/cdrom-generic.cpp \
+ generic/RTCrStoreCreateSnapshotById-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
@@ -1057,9 +1074,12 @@ RuntimeR3_SOURCES.freebsd = \
r3/posix/timer-posix.cpp \
r3/posix/tls-posix.cpp \
r3/posix/utf8-posix.cpp
+RuntimeR3_SOURCES.freebsd.x86 += common/string/memrchr.asm
+RuntimeR3_SOURCES.freebsd.amd64 += common/string/memrchr.asm
RuntimeR3_SOURCES.solaris = \
generic/cdrom-generic.cpp \
+ generic/RTCrStoreCreateSnapshotById-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
@@ -1124,9 +1144,11 @@ RuntimeR3_SOURCES.solaris = \
r3/solaris/RTSystemShutdown-solaris.cpp \
r3/solaris/thread-affinity-solaris.cpp
RuntimeR3_SOURCES.solaris.amd64 = \
+ common/string/memrchr.asm \
r3/solaris/coredumper-solaris.cpp \
r3/solaris/RTSystemQueryDmiString-solaris.cpp
RuntimeR3_SOURCES.solaris.x86 = \
+ common/string/memrchr.asm \
r3/solaris/coredumper-solaris.cpp \
r3/solaris/RTSystemQueryDmiString-solaris.cpp
RuntimeR3_SOURCES.solaris.sparc32 = \
@@ -1135,6 +1157,7 @@ RuntimeR3_SOURCES.solaris.sparc64 = \
generic/RTSystemQueryDmiString-generic.cpp
RuntimeR3_SOURCES.haiku = \
+ generic/RTCrStoreCreateSnapshotById-generic.cpp \
generic/RTDirQueryInfo-generic.cpp \
generic/RTDirSetTimes-generic.cpp \
generic/RTFileMove-generic.cpp \
@@ -1195,6 +1218,8 @@ RuntimeR3_SOURCES.haiku = \
r3/posix/timelocal-posix.cpp \
r3/posix/tls-posix.cpp \
r3/posix/utf8-posix.cpp
+RuntimeR3_SOURCES.haiku.x86 += common/string/memrchr.asm
+RuntimeR3_SOURCES.haiku.amd64 += common/string/memrchr.asm
## PORTME: Porters add their selection of platform specific files for Ring-3 here.
@@ -1310,8 +1335,9 @@ VBoxRT_SOURCES := \
common/checksum/crc32-zlib.cpp \
common/misc/aiomgr.cpp
ifdef VBOX_WITH_LIBCURL
- VBoxRT_SOURCES += common/misc/s3.cpp
- VBoxRT_SOURCES += common/misc/http.cpp
+ VBoxRT_SOURCES += \
+ common/misc/s3.cpp \
+ generic/http-curl.cpp
endif
VBoxRT_SOURCES.$(KBUILD_TARGET) = $(RuntimeR3_SOURCES.$(KBUILD_TARGET))
VBoxRT_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH) := $(RuntimeR3_SOURCES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))
@@ -1380,7 +1406,13 @@ VBoxRT_LIBS.win = \
$(PATH_SDK_$(VBOX_WINDDK)_LIB)/vccomsup.lib \
$(PATH_SDK_$(VBOX_WINDDK)_LIB)/wbemuuid.lib \
$(PATH_TOOL_$(VBOX_VCC_TOOL)_LIB)/delayimp.lib
-VBoxRT_LDFLAGS.darwin = -framework IOKit -framework CoreFoundation -framework CoreServices -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxRT.dylib
+VBoxRT_LDFLAGS.darwin = \
+ -framework IOKit \
+ -framework CoreFoundation \
+ -framework CoreServices \
+ -framework Security \
+ -framework SystemConfiguration \
+ -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxRT.dylib
VBoxRT_LDFLAGS.win = /MANIFEST \
/delayload:gdi32.dll \
/delayload:user32.dll \
@@ -1847,6 +1879,7 @@ RuntimeR0Drv_SOURCES.linux = \
generic/RTLogWriteStdOut-stub-generic.cpp \
generic/RTMpGetCoreCount-generic.cpp \
generic/mppresent-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
r0drv/linux/alloc-r0drv-linux.c \
r0drv/linux/assert-r0drv-linux.c \
r0drv/linux/initterm-r0drv-linux.c \
@@ -1978,6 +2011,7 @@ RuntimeR0Drv_SOURCES.win = \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
nt/RTErrConvertFromNtStatus.cpp \
r0drv/generic/threadctxhooks-r0drv-generic.cpp \
r0drv/memobj-r0drv.cpp \
@@ -2017,6 +2051,7 @@ RuntimeR0Drv_SOURCES.darwin = \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
generic/mppresent-generic.cpp \
generic/timer-generic.cpp \
r0drv/generic/mpnotification-r0drv-generic.cpp \
@@ -2114,6 +2149,7 @@ RuntimeR0Drv_SOURCES.freebsd = \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTLogWriteDebugger-generic.cpp \
generic/RTLogWriteStdOut-stub-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
@@ -2144,6 +2180,7 @@ RuntimeR0Drv_SOURCES.solaris = \
generic/RTAssertShouldPanic-generic.cpp \
generic/RTLogWriteStdOut-stub-generic.cpp \
generic/RTMpGetCoreCount-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
r0drv/memobj-r0drv.cpp \
@@ -2179,6 +2216,7 @@ RuntimeR0Drv_SOURCES.haiku = \
common/string/memcmp.asm \
common/string/strchr.asm \
generic/RTAssertShouldPanic-generic.cpp \
+ generic/RTMpOnPair-generic.cpp \
generic/RTTimerCreate-generic.cpp \
generic/mppresent-generic.cpp \
r0drv/generic/RTMpIsCpuWorkPending-r0drv-generic.cpp \
diff --git a/src/VBox/Runtime/common/checksum/alt-sha1.cpp b/src/VBox/Runtime/common/checksum/alt-sha1.cpp
index 2c499fa..52209e6 100644
--- a/src/VBox/Runtime/common/checksum/alt-sha1.cpp
+++ b/src/VBox/Runtime/common/checksum/alt-sha1.cpp
@@ -441,7 +441,7 @@ RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
RT_EXPORT_SYMBOL(RTSha1Update);
-RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+static void rtSha1FinalInternal(PRTSHA1CONTEXT pCtx)
{
Assert(pCtx->AltPrivate.cbMessage < UINT64_MAX / 2);
@@ -480,12 +480,22 @@ RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE
pCtx->AltPrivate.auH[2] = RT_H2BE_U32(pCtx->AltPrivate.auH[2]);
pCtx->AltPrivate.auH[3] = RT_H2BE_U32(pCtx->AltPrivate.auH[3]);
pCtx->AltPrivate.auH[4] = RT_H2BE_U32(pCtx->AltPrivate.auH[4]);
+}
- memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA1_HASH_SIZE);
+DECLINLINE(void) rtSha1WipeCtx(PRTSHA1CONTEXT pCtx)
+{
RT_ZERO(pCtx->AltPrivate);
pCtx->AltPrivate.cbMessage = UINT64_MAX;
}
+
+
+RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE])
+{
+ rtSha1FinalInternal(pCtx);
+ memcpy(pabDigest, &pCtx->AltPrivate.auH[0], RTSHA1_HASH_SIZE);
+ rtSha1WipeCtx(pCtx);
+}
RT_EXPORT_SYMBOL(RTSha1Final);
@@ -499,3 +509,17 @@ RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA1_HA
RT_EXPORT_SYMBOL(RTSha1);
+RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ rtSha1FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA1_HASH_SIZE) == 0;
+
+ rtSha1WipeCtx(&Ctx);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha1Check);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha256.cpp b/src/VBox/Runtime/common/checksum/alt-sha256.cpp
index d0e02a5..2b74f1c 100644
--- a/src/VBox/Runtime/common/checksum/alt-sha256.cpp
+++ b/src/VBox/Runtime/common/checksum/alt-sha256.cpp
@@ -606,6 +606,21 @@ RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA25
RT_EXPORT_SYMBOL(RTSha256);
+RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ rtSha256FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA256_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha256Check);
+
+
/*
* SHA-224 is just SHA-256 with different initial values an a truncated result.
@@ -651,3 +666,18 @@ RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA22
}
RT_EXPORT_SYMBOL(RTSha224);
+
+RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ rtSha256FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA224_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha224Check);
+
diff --git a/src/VBox/Runtime/common/checksum/alt-sha512.cpp b/src/VBox/Runtime/common/checksum/alt-sha512.cpp
index f7e7e20..ba6ae63 100644
--- a/src/VBox/Runtime/common/checksum/alt-sha512.cpp
+++ b/src/VBox/Runtime/common/checksum/alt-sha512.cpp
@@ -595,6 +595,21 @@ RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA51
RT_EXPORT_SYMBOL(RTSha512);
+RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512Check);
+
+
/*
* SHA-384 is just SHA-512 with different initial values an a truncated result.
@@ -642,6 +657,21 @@ RTDECL(void) RTSha384(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA38
RT_EXPORT_SYMBOL(RTSha384);
+RTDECL(bool) RTSha384Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA384_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha384Check);
+
+
/*
* SHA-512/224 is just SHA-512 with different initial values an a truncated result.
*/
@@ -688,6 +718,21 @@ RTDECL(void) RTSha512t224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTS
RT_EXPORT_SYMBOL(RTSha512t224);
+RTDECL(bool) RTSha512t224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512T224_HASH_SIZE])
+{
+ RTSHA512T224CONTEXT Ctx;
+ RTSha512t224Init(&Ctx);
+ RTSha512t224Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512T224_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512t224Check);
+
+
/*
* SHA-512/256 is just SHA-512 with different initial values an a truncated result.
*/
@@ -733,3 +778,18 @@ RTDECL(void) RTSha512t256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTS
}
RT_EXPORT_SYMBOL(RTSha512t256);
+
+RTDECL(bool) RTSha512t256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabHash[RTSHA512T256_HASH_SIZE])
+{
+ RTSHA512T256CONTEXT Ctx;
+ RTSha512t256Init(&Ctx);
+ RTSha512t256Update(&Ctx, pvBuf, cbBuf);
+ rtSha512FinalInternal(&Ctx);
+
+ bool fRet = memcmp(pabHash, &Ctx.AltPrivate.auH[0], RTSHA512T256_HASH_SIZE) == 0;
+
+ RT_ZERO(Ctx.AltPrivate.auH);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512t256Check);
+
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha1.cpp b/src/VBox/Runtime/common/checksum/openssl-sha1.cpp
index db28550..e1b4e98 100644
--- a/src/VBox/Runtime/common/checksum/openssl-sha1.cpp
+++ b/src/VBox/Runtime/common/checksum/openssl-sha1.cpp
@@ -36,6 +36,8 @@
#include <iprt/sha.h>
#include <iprt/assert.h>
+#include <iprt/string.h>
+
AssertCompile(RT_SIZEOFMEMB(RTSHA1CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA1CONTEXT, Private));
@@ -50,6 +52,20 @@ RTDECL(void) RTSha1(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA1_HA
RT_EXPORT_SYMBOL(RTSha1);
+RTDECL(bool) RTSha1Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA1_HASH_SIZE])
+{
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+ RTSha1Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA1_HASH_SIZE];
+ RTSha1Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA1_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha1Check);
+
+
RTDECL(void) RTSha1Init(PRTSHA1CONTEXT pCtx)
{
SHA1_Init(&pCtx->Private);
@@ -64,7 +80,7 @@ RTDECL(void) RTSha1Update(PRTSHA1CONTEXT pCtx, const void *pvBuf, size_t cbBuf)
RT_EXPORT_SYMBOL(RTSha1Update);
-RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[32])
+RTDECL(void) RTSha1Final(PRTSHA1CONTEXT pCtx, uint8_t pabDigest[RTSHA1_HASH_SIZE])
{
SHA1_Final((unsigned char *)&pabDigest[0], &pCtx->Private);
}
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha256.cpp b/src/VBox/Runtime/common/checksum/openssl-sha256.cpp
index 6686017..93416ab 100644
--- a/src/VBox/Runtime/common/checksum/openssl-sha256.cpp
+++ b/src/VBox/Runtime/common/checksum/openssl-sha256.cpp
@@ -36,6 +36,8 @@
#include <iprt/sha.h>
#include <iprt/assert.h>
+#include <iprt/string.h>
+
AssertCompile(RT_SIZEOFMEMB(RTSHA256CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA256CONTEXT, Private));
@@ -50,6 +52,20 @@ RTDECL(void) RTSha256(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA25
RT_EXPORT_SYMBOL(RTSha256);
+RTDECL(bool) RTSha256Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA256_HASH_SIZE])
+{
+ RTSHA256CONTEXT Ctx;
+ RTSha256Init(&Ctx);
+ RTSha256Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA256_HASH_SIZE];
+ RTSha256Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA256_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha256Check);
+
+
RTDECL(void) RTSha256Init(PRTSHA256CONTEXT pCtx)
{
SHA256_Init(&pCtx->Private);
@@ -86,6 +102,20 @@ RTDECL(void) RTSha224(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA22
RT_EXPORT_SYMBOL(RTSha224);
+RTDECL(bool) RTSha224Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA224_HASH_SIZE])
+{
+ RTSHA224CONTEXT Ctx;
+ RTSha224Init(&Ctx);
+ RTSha224Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA224_HASH_SIZE];
+ RTSha224Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA224_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha224Check);
+
+
RTDECL(void) RTSha224Init(PRTSHA224CONTEXT pCtx)
{
SHA224_Init(&pCtx->Private);
diff --git a/src/VBox/Runtime/common/checksum/openssl-sha512.cpp b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp
index 9f3ad45..53fddec 100644
--- a/src/VBox/Runtime/common/checksum/openssl-sha512.cpp
+++ b/src/VBox/Runtime/common/checksum/openssl-sha512.cpp
@@ -36,6 +36,8 @@
#include <iprt/sha.h>
#include <iprt/assert.h>
+#include <iprt/string.h>
+
AssertCompile(RT_SIZEOFMEMB(RTSHA512CONTEXT, abPadding) >= RT_SIZEOFMEMB(RTSHA512CONTEXT, Private));
@@ -50,6 +52,20 @@ RTDECL(void) RTSha512(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA51
RT_EXPORT_SYMBOL(RTSha512);
+RTDECL(bool) RTSha512Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA512_HASH_SIZE])
+{
+ RTSHA512CONTEXT Ctx;
+ RTSha512Init(&Ctx);
+ RTSha512Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA512_HASH_SIZE];
+ RTSha512Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA512_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha512Check);
+
+
RTDECL(void) RTSha512Init(PRTSHA512CONTEXT pCtx)
{
SHA512_Init(&pCtx->Private);
@@ -87,6 +103,20 @@ RTDECL(void) RTSha384(const void *pvBuf, size_t cbBuf, uint8_t pabDigest[RTSHA38
RT_EXPORT_SYMBOL(RTSha384);
+RTDECL(bool) RTSha384Check(const void *pvBuf, size_t cbBuf, uint8_t const pabDigest[RTSHA384_HASH_SIZE])
+{
+ RTSHA384CONTEXT Ctx;
+ RTSha384Init(&Ctx);
+ RTSha384Update(&Ctx, pvBuf, cbBuf);
+ uint8_t abActualDigest[RTSHA384_HASH_SIZE];
+ RTSha384Final(&Ctx, abActualDigest);
+ bool fRet = memcmp(pabDigest, abActualDigest, RTSHA384_HASH_SIZE) == 0;
+ RT_ZERO(abActualDigest);
+ return fRet;
+}
+RT_EXPORT_SYMBOL(RTSha384Check);
+
+
RTDECL(void) RTSha384Init(PRTSHA384CONTEXT pCtx)
{
SHA384_Init(&pCtx->Private);
diff --git a/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromFile.cpp b/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromFile.cpp
deleted file mode 100644
index b79eded..0000000
--- a/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromFile.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/* $Id: RTCrStoreCertAddFromFile.cpp $ */
-/** @file
- * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromFile.
- */
-
-/*
- * Copyright (C) 2006-2014 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include "internal/iprt.h"
-#include <iprt/crypto/store.h>
-
-#include <iprt/assert.h>
-#include <iprt/err.h>
-#include <iprt/crypto/pem.h>
-
-
-/*******************************************************************************
-* Global Variables *
-*******************************************************************************/
-static RTCRPEMMARKERWORD const g_aWords_Certificate[] = { { RT_STR_TUPLE("CERTIFICATE") } };
-/** X509 Certificate markers. */
-static RTCRPEMMARKER const g_aCertificateMarkers[] = { { g_aWords_Certificate, RT_ELEMENTS(g_aWords_Certificate) } };
-
-
-#if 0
-RTDECL(int) RTCrX509Certificates_ReadFromFile(const char *pszFilename, uint32_t fFlags,
- PRTCRX509CERTIFICATES pCertificates, PRTERRINFO pErrInfo)
-{
- AssertReturn(!fFlags, VERR_INVALID_FLAGS);
- PCRTCRPEMSECTION pSectionHead;
- int rc = RTCrPemReadFile(pszFilename, 0, g_aCertificateMarkers, RT_ELEMENTS(g_aCertificateMarkers), &pSectionHead, pErrInfo);
- if (RT_SUCCESS(rc))
- {
- pCertificates->Allocation
-
- PCRTCRPEMSECTION pCurSec = pSectionHead;
- while (pCurSec)
- {
-
- pCurSec = pCurSec->pNext;
- }
-
- RTCrPemFreeSections(pSectionHead);
- }
- return rc;
-}
-#endif
-
-
-RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
-{
- AssertReturn(!fFlags, VERR_INVALID_FLAGS);
-#if 0
- RTCRX509CERTIFICATES Certs;
- int rc = RTCrX509Certificates_ReadFromFile(pszFilename, 0, &Certs, pErrInfo);
- if (RT_SUCCESS(rc))
- {
- for (uint32_t i = 0; i < Certs.cCerts; i++)
- {
- int rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER,
- RTASN1CORE_GET_RAW_ASN1_PTR(&Certs.paCerts[i].SeqCore.Asn1Core),
- RTASN1CORE_GET_RAW_ASN1_SIZE(&Certs.paCerts[i].SeqCore.Asn1Core),
- RT_SUCCESS(rc) ? pErrInfo : NULL);
- if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
- rc = rc2;
- }
-
- RTAsn1Destroy(&Certs.SetCore.Asn1Core);
- }
- return rc;
-#else
-
- PCRTCRPEMSECTION pSectionHead;
- int rc = RTCrPemReadFile(pszFilename, 0, g_aCertificateMarkers, RT_ELEMENTS(g_aCertificateMarkers), &pSectionHead, pErrInfo);
- if (RT_SUCCESS(rc))
- {
- PCRTCRPEMSECTION pCurSec = pSectionHead;
- while (pCurSec)
- {
- int rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER, pCurSec->pbData, pCurSec->cbData,
- RT_SUCCESS(rc) ? pErrInfo : NULL);
- if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
- rc = rc2;
- pCurSec = pCurSec->pNext;
- }
-
- RTCrPemFreeSections(pSectionHead);
- }
- return rc;
-#endif
-}
-
diff --git a/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp b/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp
new file mode 100644
index 0000000..94a4218
--- /dev/null
+++ b/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp
@@ -0,0 +1,310 @@
+/* $Id: RTCrStoreCertAddFromJavaKeyStore.cpp $ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromJavaKeyStore.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_CRYPTO
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+#include <iprt/log.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The java key store magic number (file endian). */
+#define JKS_MAGIC RT_H2BE_U32_C(UINT32_C(0xfeedfeed))
+/** Java key store format version 2 (file endian). */
+#define JKS_VERSION_2 RT_H2BE_U32_C(2)
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Java key store (JKS) header.
+ */
+typedef struct JKSHEADER
+{
+ /** The magic (big endian) - JKS_MAGIC. */
+ uint32_t uMagic;
+ /** Format version number (big endian) - JKS_VERSION_2. */
+ uint32_t uVersion;
+ /** The number of keystore entries (big endian). */
+ uint32_t cEntries;
+} JKSHEADER;
+/** Pointer to a const java key store header. */
+typedef JKSHEADER const *PCJKSHEADER;
+
+
+RTDECL(int) RTCrStoreCertAddFromJavaKeyStoreInMem(RTCRSTORE hStore, uint32_t fFlags, void const *pvContent, size_t cbContent,
+ const char *pszErrorName, PRTERRINFO pErrInfo)
+{
+ uint8_t const *pbContent = (uint8_t const *)pvContent;
+
+ /*
+ * Check the header.
+ */
+ if (cbContent < sizeof(JKSHEADER) + RTSHA1_HASH_SIZE)
+ return RTErrInfoAddF(pErrInfo, VERR_WRONG_TYPE /** @todo better status codes */,
+ " Too small (%zu bytes) for java key store (%s)", cbContent, pszErrorName);
+ PCJKSHEADER pHdr = (PCJKSHEADER)pbContent;
+ if (pHdr->uMagic != JKS_MAGIC)
+ return RTErrInfoAddF(pErrInfo, VERR_WRONG_TYPE /** @todo better status codes */,
+ " Not java key store magic %#x (%s)", RT_BE2H_U32(pHdr->uMagic), pszErrorName);
+ if (pHdr->uVersion != JKS_VERSION_2)
+ return RTErrInfoAddF(pErrInfo, VERR_WRONG_TYPE /** @todo better status codes */,
+ " Unsupported java key store version %#x (%s)", RT_BE2H_U32(pHdr->uVersion), pszErrorName);
+ uint32_t const cEntries = RT_BE2H_U32(pHdr->cEntries);
+ if (cEntries > cbContent / 24) /* 24 = 4 for type, 4+ alias, 8 byte timestamp, 4 byte len, "X.509" or 4 cert count */
+ return RTErrInfoAddF(pErrInfo, VERR_WRONG_TYPE /** @todo better status codes */,
+ " Entry count %u is to high for %zu byte JKS (%s)", cEntries, cbContent, pszErrorName);
+
+ /*
+ * Here we should check the store signature. However, it always includes
+ * some kind of password, and that's somewhere we don't want to go right
+ * now. Later perhaps.
+ *
+ * We subtract it from the content size to make EOF checks simpler.
+ */
+ int rc = VINF_SUCCESS;
+#if 0 /* later */
+ RTSHA1CONTEXT Ctx;
+ RTSha1Init(&Ctx);
+
+ const char *pszCur = pszPassword;
+ for (;;)
+ {
+ RTUNICP Cp;
+ rc = RTStrGetCpEx(&pszCur, &Cp);
+ AssertRCReturn(rc, rc);
+ if (!Cp)
+ break;
+ uint8_t abWChar[2];
+ abWChar[0] = RT_BYTE2(Cp);
+ abWChar[1] = RT_BYTE1(Cp);
+ RTSha1Update(&Ctx, &abWChar, sizeof(abWChar));
+ }
+
+ RTSha1Update(&Ctx, RT_STR_TUPLE("Mighty Aphrodite"));
+
+ RTSha1Update(&Ctx, pbContent, cbContent - RTSHA1_HASH_SIZE);
+
+ uint8_t abSignature[RTSHA1_HASH_SIZE];
+ RTSha1Final(&Ctx, abSignature);
+
+ if (memcmp(&pbContent[cbContent - RTSHA1_HASH_SIZE], abSignature, RTSHA1_HASH_SIZE) != 0)
+ {
+ rc = RTErrInfoAddF(pErrInfo, VERR_MISMATCH, " File SHA-1 signature mismatch, %.*Rhxs instead of %.*Rhxs, for '%s'",
+ RTSHA1_HASH_SIZE, abSignature,
+ RTSHA1_HASH_SIZE, &pbContent[cbContent - RTSHA1_HASH_SIZE],
+ pszErrorName);
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ return rc;
+ }
+#endif
+ cbContent -= RTSHA1_HASH_SIZE;
+
+
+ /*
+ * A bunch of macros to make decoding easier.
+ */
+#define ENSURE_CONTENT_OR_BREAK_EX(a_cbNeeded, a_pszWhat) \
+ do { \
+ if (RT_LIKELY(off + (a_cbNeeded) <= cbContent)) \
+ { /* likely */ } \
+ else \
+ { \
+ rc = RTErrInfoAddF(pErrInfo, VERR_EOF, " Unexpected end of data at %#x need %u bytes for %s (entry #%u in %s)", \
+ off, a_cbNeeded, a_pszWhat, iEntry, pszErrorName); \
+ break; \
+ } \
+ } while (0)
+#define ENSURE_CONTENT_OR_BREAK(a_Var) ENSURE_CONTENT_OR_BREAK_EX(sizeof(a_Var), #a_Var)
+#define GET_BE_U32_OR_BREAK(a_uVar) \
+ do { \
+ ENSURE_CONTENT_OR_BREAK(a_uVar); \
+ AssertCompile(sizeof(a_uVar) == sizeof(uint32_t)); \
+ a_uVar = RT_MAKE_U32_FROM_U8(pbContent[off + 3], pbContent[off + 2], pbContent[off + 1], pbContent[off + 0]); \
+ off += sizeof(uint32_t); \
+ } while (0)
+#define GET_BE_U16_OR_BREAK(a_uVar) \
+ do { \
+ ENSURE_CONTENT_OR_BREAK(a_uVar); \
+ AssertCompile(sizeof(a_uVar) == sizeof(uint16_t)); \
+ a_uVar = RT_MAKE_U16(pbContent[off + 1], pbContent[off + 0]); \
+ off += sizeof(uint16_t); \
+ } while (0)
+#define SKIP_CONTENT_BYTES_OR_BREAK(a_cbToSkip, a_pszWhat) \
+ do { \
+ ENSURE_CONTENT_OR_BREAK_EX(a_cbToSkip, a_pszWhat); \
+ off += a_cbToSkip; \
+ } while (0)
+#define CHECK_OR_BREAK(a_Expr, a_RTErrInfoAddFArgs) \
+ do { \
+ if (RT_LIKELY(a_Expr)) \
+ { /* likely */ } \
+ else \
+ { \
+ rc = RTErrInfoAddF a_RTErrInfoAddFArgs; \
+ break; \
+ } \
+ } while (0)
+
+ /*
+ * Work our way thru the keystore.
+ */
+ Log(("JKS: %u entries - '%s'\n", cEntries, pszErrorName));
+ size_t off = sizeof(JKSHEADER);
+ uint32_t iEntry = 0;
+ for (;;)
+ {
+ size_t const offEntry = off; NOREF(offEntry);
+
+ /* The entry type. */
+ uint32_t uType;
+ GET_BE_U32_OR_BREAK(uType);
+ CHECK_OR_BREAK(uType == 1 || uType == 2,
+ (pErrInfo, VERR_WRONG_TYPE, " uType=%#x (entry #%u in %s)", uType, iEntry, pszErrorName));
+
+ /* Skip the alias string. */
+ uint16_t cbAlias;
+ GET_BE_U16_OR_BREAK(cbAlias);
+ SKIP_CONTENT_BYTES_OR_BREAK(cbAlias, "szAlias");
+
+ /* Skip the creation timestamp. */
+ SKIP_CONTENT_BYTES_OR_BREAK(sizeof(uint64_t), "tsCreated");
+
+ uint32_t cTrustCerts = 0;
+ if (uType == 1)
+ {
+ /*
+ * It is a private key.
+ */
+ Log(("JKS: %#08zx: entry #%u: Private key\n", offEntry, iEntry));
+
+ /* The encoded key. */
+ uint32_t cbKey;
+ GET_BE_U32_OR_BREAK(cbKey);
+ SKIP_CONTENT_BYTES_OR_BREAK(cbKey, "key data");
+
+ /* The number of trust certificates following it. */
+ GET_BE_U32_OR_BREAK(cTrustCerts);
+ }
+ else if (uType == 2)
+ {
+ /*
+ * It is a certificate.
+ */
+ Log(("JKS: %#08zx: entry #%u: Trust certificate\n", offEntry, iEntry));
+ cTrustCerts = 1;
+ }
+ else
+ AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR_2);
+
+ /*
+ * Decode trust certificates. Keys have 0 or more of these associated with them.
+ */
+ for (uint32_t iCert = 0; iCert < cTrustCerts; iCert++)
+ {
+ /* X.509 signature */
+ static const char a_achCertType[] = { 0, 5, 'X', '.', '5', '0', '9' };
+ ENSURE_CONTENT_OR_BREAK(a_achCertType);
+ CHECK_OR_BREAK(memcmp(&pbContent[off], a_achCertType, sizeof(a_achCertType)) == 0,
+ (pErrInfo, VERR_WRONG_TYPE, " Unsupported certificate type %.7Rhxs (entry #%u in %s)",
+ &pbContent[off], iEntry, pszErrorName));
+ off += sizeof(a_achCertType);
+
+ /* The encoded certificate length. */
+ uint32_t cbEncoded;
+ GET_BE_U32_OR_BREAK(cbEncoded);
+ ENSURE_CONTENT_OR_BREAK_EX(cbEncoded, "certificate data");
+ Log(("JKS: %#08zx: %#x certificate bytes\n", off, cbEncoded, cbEncoded));
+
+ /* Try add the certificate. */
+ RTERRINFOSTATIC StaticErrInfo;
+ int rc2 = RTCrStoreCertAddEncoded(hStore,
+ RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+ &pbContent[off], cbEncoded, RTErrInfoInitStatic(&StaticErrInfo));
+ if (RT_FAILURE(rc2))
+ {
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ rc = RTErrInfoAddF(pErrInfo, rc2, " entry #%u: %s", iEntry, StaticErrInfo.Core.pszMsg);
+ else
+ rc = RTErrInfoAddF(pErrInfo, rc2, " entry #%u: %Rrc adding cert", iEntry, rc2);
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ break;
+ }
+ off += cbEncoded;
+ }
+
+ /*
+ * Advance.
+ */
+ iEntry++;
+ if (iEntry >= cEntries)
+ {
+ if (off != cbContent)
+ rc = RTErrInfoAddF(pErrInfo, VERR_TOO_MUCH_DATA, " %zu tailing bytes (%s)", cbContent - off, pszErrorName);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+RTDECL(int) RTCrStoreCertAddFromJavaKeyStore(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
+{
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+
+ /*
+ * Read the whole thing into memory as that's much more convenient to work
+ * with and we don't expect a java key store to take up a lot of space.
+ */
+ size_t cbContent;
+ void *pvContent;
+ int rc = RTFileReadAllEx(pszFilename, 0, 32U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
+ RTFileReadAllFree(pvContent, cbContent);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromJavaKeyStore);
+
diff --git a/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp b/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp
new file mode 100644
index 0000000..68f7ae4
--- /dev/null
+++ b/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp
@@ -0,0 +1,247 @@
+/* $Id: RTCrStoreCertAddWantedFromFishingExpedition.cpp $ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromFishingExpedition.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+
+#include "x509-internal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef RT_OS_WINDOWS
+# define PREFIX_UNIXROOT "${SystemDrive}/cygwin"
+#elif defined(RT_OS_OS2)
+# define PREFIX_UNIXROOT "/@unixroot@"
+#else
+# define PREFIX_UNIXROOT
+#endif
+
+
+/**
+ * Count the number of found certificates.
+ *
+ * @returns Number found.
+ * @param afFound Indicator array.
+ * @param cWanted Number of wanted certificates.
+ */
+DECLINLINE(size_t) rtCrStoreCountFound(bool const *afFound, size_t cWanted)
+{
+ size_t cFound = 0;
+ while (cWanted-- > 0)
+ if (afFound[cWanted])
+ cFound++;
+ return cFound;
+}
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags,
+ PCRTCRCERTWANTED paWanted, size_t cWanted,
+ bool *pafFound, PRTERRINFO pErrInfo)
+{
+ int rc = VINF_SUCCESS;
+ int rc2;
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+ fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR; /* force these! */
+ AssertReturn(cWanted, VERR_NOT_FOUND);
+ for (uint32_t i = 0; i < cWanted; i++)
+ {
+ AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+ AssertReturn( paWanted[i].pszSubject
+ || paWanted[i].fSha1Fingerprint
+ || paWanted[i].fSha512Fingerprint,
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Make sure we've got a result array.
+ */
+ bool *pafFoundFree = NULL;
+ if (!pafFound)
+ {
+ pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+ AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+ }
+
+ /*
+ * Search the user and system stores first.
+ */
+ bool fAllFound = false;
+ RTCRSTORE hTmpStore;
+ for (int iStoreId = RTCRSTOREID_INVALID + 1; iStoreId < RTCRSTOREID_END; iStoreId++)
+ {
+ rc2 = RTCrStoreCreateSnapshotById(&hTmpStore, (RTCRSTOREID)iStoreId, NULL);
+ if (RT_SUCCESS(rc2))
+ {
+ rc2 = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
+ RTCrStoreRelease(hTmpStore);
+ fAllFound = rc2 == VINF_SUCCESS;
+ if (fAllFound)
+ break;
+ }
+ }
+
+ /*
+ * Search alternative file based stores.
+ */
+ if (!fAllFound)
+ {
+ static const char * const s_apszFiles[] =
+ {
+ PREFIX_UNIXROOT "/usr/share/ca-certificates/trust-source/mozilla.neutral-trust.crt",
+ PREFIX_UNIXROOT "/usr/share/ca-certificates/trust-source/mozilla.trust.crt",
+ PREFIX_UNIXROOT "/usr/share/doc/mutt/samples/ca-bundle.crt",
+ PREFIX_UNIXROOT "/usr/jdk/latest/jre/lib/security/cacerts",
+ PREFIX_UNIXROOT "/usr/share/curl/curl-ca-bundle.crt",
+#ifdef RT_OS_DARWIN
+ "/opt/local/share/curl/curl-ca-bundle.crt",
+ "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts",
+ "/System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts",
+ "/System/Library/Java/Support/CoreDeploy.bundle/Contents/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts",
+ "/System/Library/Java/Support/Deploy.bundle/Contents/Home/lib/security/cacerts",
+ "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/lib/security/cacerts",
+ "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms/java/lib/security/cacerts",
+ "/Applications/Xcode-beta.app/Contents/Applications/Application Loader.app/Contents/itms/java/lib/security/cacerts",
+ "/System/Library/Java/JavaVirtualMachines/*/Contents/Home/lib/security/cacerts",
+#endif
+#ifdef RT_OS_LINUX
+ PREFIX_UNIXROOT "/etc/ssl/certs/java/cacerts",
+ PREFIX_UNIXROOT "/usr/lib/j*/*/jre/lib/security/cacerts",
+ PREFIX_UNIXROOT "/opt/*/jre/lib/security/cacerts",
+#endif
+#ifdef RT_OS_SOLARIS
+ PREFIX_UNIXROOT "/usr/java/jre/lib/security/cacerts",
+ PREFIX_UNIXROOT "/usr/jdk/instances/*/jre/lib/security/cacerts",
+#endif
+#ifdef RT_OS_WINDOWS
+ "${AllProgramFiles}/Git/bin/curl-ca-bundle.crt",
+ "${AllProgramFiles}/Mercurial/hgrc.d/cacert.pem",
+ "${AllProgramFiles}/Java/jre*/lib/security/cacerts",
+ "${AllProgramFiles}/Java/jdk*/jre/lib/security/cacerts",
+ "${AllProgramFiles}/HexChat/cert.pem",
+ "${SystemDrive}/BitNami/*/git/bin/curl-ca-bundle.crt",
+ "${SystemDrive}/BitNami/*/heroku/data/cacert.pem",
+ "${SystemDrive}/BitNami/*/heroku/vendor/gems/excon*/data/cacert.pem",
+ "${SystemDrive}/BitNami/*/php/PEAR/AWSSDKforPHP/lib/requstcore/cacert.pem",
+#endif
+ };
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_apszFiles) && !fAllFound; i++)
+ {
+ PCRTPATHGLOBENTRY pResultHead;
+ rc2 = RTPathGlob(s_apszFiles[i], RTPATHGLOB_F_NO_DIRS, &pResultHead, NULL);
+ if (RT_SUCCESS(rc2))
+ {
+ for (PCRTPATHGLOBENTRY pCur = pResultHead; pCur; pCur = pCur->pNext)
+ {
+ rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, pCur->szPath, paWanted, cWanted, pafFound, pErrInfo);
+ fAllFound = rc2 == VINF_SUCCESS;
+ if (fAllFound)
+ break;
+ }
+ RTPathGlobFree(pResultHead);
+ }
+ }
+ }
+
+ /*
+ * Search alternative directory based stores.
+ */
+ if (!fAllFound)
+ {
+ static const char * const s_apszFiles[] =
+ {
+ PREFIX_UNIXROOT "/usr/share/ca-certificates/mozilla/",
+#ifdef RT_OS_DARWIN
+ "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/ssl_certs/",
+#endif
+#ifdef RT_OS_SOLARIS
+ "/etc/certs/",
+ "/etc/crypto/certs/",
+#endif
+#ifdef RT_OS_WINDOWS
+ "${AllProgramFiles}/Git/ssl/certs/",
+ "${AllProgramFiles}/Git/ssl/certs/expired/",
+ "${AllProgramFiles}/Common Files/Apple/Internet Services/security.resources/roots/",
+ "${AllProgramFiles}/Raptr/ca-certs/",
+ "${SystemDrive}/Bitname/*/git/ssl/certs/",
+ "${SystemDrive}/Bitnami/*/git/ssl/certs/expired/",
+#endif
+ };
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_apszFiles) && !fAllFound; i++)
+ {
+ PCRTPATHGLOBENTRY pResultHead;
+ rc2 = RTPathGlob(s_apszFiles[i], RTPATHGLOB_F_ONLY_DIRS, &pResultHead, NULL);
+ if (RT_SUCCESS(rc2))
+ {
+ for (PCRTPATHGLOBENTRY pCur = pResultHead; pCur; pCur = pCur->pNext)
+ {
+ rc2 = RTCrStoreCertAddWantedFromDir(hStore, fFlags, pCur->szPath, NULL /*paSuffixes*/, 0 /*cSuffixes*/,
+ paWanted, cWanted, pafFound, pErrInfo);
+ fAllFound = rc2 == VINF_SUCCESS;
+ if (fAllFound)
+ break;
+ }
+ RTPathGlobFree(pResultHead);
+ }
+ }
+ }
+
+ /*
+ * If all found, return VINF_SUCCESS, otherwise warn that we didn't find everything.
+ */
+ if (RT_SUCCESS(rc))
+ {
+ size_t cFound = rtCrStoreCountFound(pafFound, cWanted);
+ Assert(cFound == cWanted || !fAllFound);
+ if (cFound == cWanted)
+ rc = VINF_SUCCESS;
+ else if (cFound > 0)
+ rc = VWRN_NOT_FOUND;
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+ if (pafFoundFree)
+ RTMemTmpFree(pafFoundFree);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFishingExpedition);
+
+
diff --git a/src/VBox/Runtime/common/crypto/RTCrStoreCertExportAsPem.cpp b/src/VBox/Runtime/common/crypto/RTCrStoreCertExportAsPem.cpp
new file mode 100644
index 0000000..b7bc5c8
--- /dev/null
+++ b/src/VBox/Runtime/common/crypto/RTCrStoreCertExportAsPem.cpp
@@ -0,0 +1,137 @@
+/* $Id: RTCrStoreCertExportAsPem.cpp $ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertExportAsPem.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/assert.h>
+#include <iprt/base64.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/stream.h>
+
+
+
+RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename)
+{
+ /*
+ * Validate input.
+ */
+ AssertReturn(!fFlags, VERR_INVALID_FLAGS);
+
+ /*
+ * Start the enumeration first as this validates the store handle.
+ */
+ RTCRSTORECERTSEARCH Search;
+ int rc = RTCrStoreCertFindAll(hStore, &Search);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Open the file for writing.
+ *
+ * Note! We must use text and no binary here, because the base-64 API
+ * below will use host specific EOL markers, not CRLF as PEM
+ * specifies.
+ */
+ PRTSTREAM hStrm;
+ rc = RTStrmOpen(pszFilename, "w", &hStrm);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Enumerate the certificates in the store, writing them out one by one.
+ */
+ size_t cbBase64 = 0;
+ char *pszBase64 = NULL;
+ PCRTCRCERTCTX pCertCtx;
+ while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
+ {
+ const char *pszMarker;
+ switch (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK)
+ {
+ case RTCRCERTCTX_F_ENC_X509_DER: pszMarker = "CERTIFICATE"; break;
+ case RTCRCERTCTX_F_ENC_TAF_DER: pszMarker = "TRUST ANCHOR"; break;
+ default: pszMarker = NULL; break;
+ }
+ if (pszMarker && pCertCtx->cbEncoded > 0)
+ {
+ /*
+ * Do the base64 conversion first.
+ */
+ size_t cchEncoded = RTBase64EncodedLength(pCertCtx->cbEncoded);
+ if (cchEncoded < cbBase64)
+ { /* likely */ }
+ else
+ {
+ size_t cbNew = RT_ALIGN(cchEncoded + 64, 128);
+ void *pvNew = RTMemRealloc(pszBase64, cbNew);
+ if (!pvNew)
+ {
+ rc = VERR_NO_MEMORY;
+ break;
+ }
+ cbBase64 = cbNew;
+ pszBase64 = (char *)pvNew;
+ }
+ rc = RTBase64Encode(pCertCtx->pabEncoded, pCertCtx->cbEncoded, pszBase64, cbBase64, &cchEncoded);
+ if (RT_FAILURE(rc))
+ break;
+
+ RTStrmPrintf(hStrm, "-----BEGIN %s-----\n", pszMarker);
+ RTStrmWrite(hStrm, pszBase64, cchEncoded);
+ rc = RTStrmPrintf(hStrm, "\n-----END %s-----\n", pszMarker);
+ if (RT_FAILURE(rc))
+ break;
+ }
+
+ RTCrCertCtxRelease(pCertCtx);
+ }
+ if (pCertCtx)
+ RTCrCertCtxRelease(pCertCtx);
+ RTMemFree(pszBase64);
+
+ /*
+ * Flush the output file before closing.
+ */
+ int rc2 = RTStrmFlush(hStrm);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ RTStrmClearError(hStrm); /** @todo fix RTStrmClose... */
+ rc2 = RTStrmClose(hStrm);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2);
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertExportAsPem);
+
diff --git a/src/VBox/Runtime/common/crypto/pemfile.cpp b/src/VBox/Runtime/common/crypto/pemfile.cpp
index 441c96e..b72fb31 100644
--- a/src/VBox/Runtime/common/crypto/pemfile.cpp
+++ b/src/VBox/Runtime/common/crypto/pemfile.cpp
@@ -124,8 +124,7 @@ static bool rtCrPemFindMarker(uint8_t const *pbContent, size_t cbContent, size_t
*/
uint8_t const *pbSavedContent = pbContent;
size_t const cbSavedContent = cbContent;
- uint32_t iMarker = 0;
- while (iMarker < cMarkers)
+ for (uint32_t iMarker = 0; iMarker < cMarkers; iMarker++)
{
pbContent = pbSavedContent;
cbContent = cbSavedContent;
@@ -142,13 +141,16 @@ static bool rtCrPemFindMarker(uint8_t const *pbContent, size_t cbContent, size_t
pbContent += cchWord;
cbContent -= cchWord;
- if (!cbContent || !RT_C_IS_BLANK(*pbContent))
+ if (!cbContent)
+ break;
+ if (RT_C_IS_BLANK(*pbContent))
+ do
+ {
+ pbContent++;
+ cbContent--;
+ } while (cbContent > 0 && RT_C_IS_BLANK(*pbContent));
+ else if (cWords > 1 || pbContent[0] != '-')
break;
- do
- {
- pbContent++;
- cbContent--;
- } while (cbContent > 0 && RT_C_IS_BLANK(*pbContent));
cWords--;
if (cWords == 0)
@@ -174,7 +176,7 @@ static bool rtCrPemFindMarker(uint8_t const *pbContent, size_t cbContent, size_t
pbContent++, cbContent--;
if (poffEnd)
*poffEnd = pbContent - pbStart;
- if (*ppMatch)
+ if (ppMatch)
*ppMatch = &paMarkers[iMarker];
return true;
}
@@ -261,31 +263,38 @@ static int rtCrPemDecodeBase64(uint8_t const *pbContent, size_t cbContent, void
* @param pbFile The file bytes to scan.
* @param cbFile The number of bytes.
*/
-static bool rtCrPemIsBinaryFile(uint8_t *pbFile, size_t cbFile)
+static bool rtCrPemIsBinaryBlob(uint8_t const *pbFile, size_t cbFile)
{
/*
- * Assume a well formed PEM file contains only 7-bit ASCII and restricts
- * itself to the following control characters:
+ * Well formed PEM files should probably only contain 7-bit ASCII and
+ * restrict thenselfs to the following control characters:
* tab, newline, return, form feed
+ *
+ * However, if we wan't to read PEM files which contains human readable
+ * certificate details before or after each base-64 section, we can't stick
+ * to 7-bit ASCII. We could say it must be UTF-8, but that's probably to
+ * limited too. So, we'll settle for detecting binary files by control
+ * characters alone (safe enough for DER encoded stuff, I think).
*/
while (cbFile-- > 0)
{
uint8_t const b = *pbFile++;
- if ( b >= 0x7f
- || (b < 32 && b != '\t' && b != '\n' && b != '\r' && b != '\f') )
+ if (b < 32 && b != '\t' && b != '\n' && b != '\r' && b != '\f')
{
/* Ignore EOT (4), SUB (26) and NUL (0) at the end of the file. */
if ( (b == 4 || b == 26)
&& ( cbFile == 0
|| ( cbFile == 1
&& *pbFile == '\0')))
- return true;
+ return false;
+
if (b == 0 && cbFile == 0)
- return true;
- return false;
+ return false;
+
+ return true;
}
}
- return true;
+ return false;
}
@@ -296,123 +305,152 @@ RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead)
PRTCRPEMSECTION pFree = (PRTCRPEMSECTION)pSectionHead;
pSectionHead = pSectionHead->pNext;
- if (pFree->pMarker)
- {
- if (pFree->pbData)
- {
- RTMemFree(pFree->pbData);
- pFree->pbData = NULL;
- pFree->cbData = 0;
- }
+ Assert(pFree->pMarker || !pFree->pszPreamble);
- if (pFree->pszPreamble)
- {
- RTMemFree(pFree->pszPreamble);
- pFree->pszPreamble = NULL;
- pFree->cchPreamble = 0;
- }
+ if (pFree->pbData)
+ {
+ RTMemFree(pFree->pbData);
+ pFree->pbData = NULL;
+ pFree->cbData = 0;
}
- else
+
+ if (pFree->pszPreamble)
{
- RTFileReadAllFree(pFree->pbData, pFree->cbData);
- Assert(!pFree->pszPreamble);
+ RTMemFree(pFree->pszPreamble);
+ pFree->pszPreamble = NULL;
+ pFree->cchPreamble = 0;
}
- pFree->pbData = NULL;
- pFree->cbData = 0;
}
return VINF_SUCCESS;
}
-RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
- PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo)
+RTDECL(int) RTCrPemParseContent(void const *pvContent, size_t cbContent, uint32_t fFlags,
+ PCRTCRPEMMARKER paMarkers, size_t cMarkers,
+ PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo)
{
- AssertReturn(!fFlags, VERR_INVALID_FLAGS);
+ /*
+ * Input validation.
+ */
+ AssertPtr(ppSectionHead);
+ *ppSectionHead = NULL;
+ AssertReturn(cbContent, VINF_EOF);
+ AssertPtr(pvContent);
+ AssertPtr(paMarkers);
- size_t cbContent;
- uint8_t *pbContent;
- int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, (void **)&pbContent, &cbContent);
- if (RT_SUCCESS(rc))
+ /*
+ * Pre-allocate a section.
+ */
+ int rc = VINF_SUCCESS;
+ PRTCRPEMSECTION pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
+ if (pSection)
{
- PRTCRPEMSECTION pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
- if (pSection)
+ /*
+ * Try locate the first section.
+ */
+ uint8_t const *pbContent = (uint8_t const *)pvContent;
+ size_t offBegin, offEnd, offResume;
+ PCRTCRPEMMARKER pMatch;
+ if ( !rtCrPemIsBinaryBlob(pbContent, cbContent)
+ && rtCrPemFindMarkerSection(pbContent, cbContent, 0 /*offStart*/, paMarkers, cMarkers,
+ &pMatch, &offBegin, &offEnd, &offResume) )
{
- /*
- * Try locate the first section.
- */
- size_t offBegin, offEnd, offResume;
- PCRTCRPEMMARKER pMatch;
- if ( !rtCrPemIsBinaryFile(pbContent, cbContent)
- && rtCrPemFindMarkerSection(pbContent, cbContent, 0 /*offStart*/, paMarkers, cMarkers,
- &pMatch, &offBegin, &offEnd, &offResume) )
+ PCRTCRPEMSECTION *ppNext = ppSectionHead;
+ for (;;)
{
- PCRTCRPEMSECTION *ppNext = ppSectionHead;
- for (;;)
+ //pSection->pNext = NULL;
+ pSection->pMarker = pMatch;
+ //pSection->pbData = NULL;
+ //pSection->cbData = 0;
+ //pSection->pszPreamble = NULL;
+ //pSection->cchPreamble = 0;
+
+ *ppNext = pSection;
+ ppNext = &pSection->pNext;
+
+ /* Decode the section. */
+ /** @todo copy the preamble as well. */
+ int rc2 = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin,
+ (void **)&pSection->pbData, &pSection->cbData);
+ if (RT_FAILURE(rc2))
{
- //pSection->pNext = NULL;
- pSection->pMarker = pMatch;
- //pSection->pbData = NULL;
- //pSection->cbData = 0;
- //pSection->pszPreamble = NULL;
- //pSection->cchPreamble = 0;
-
- *ppNext = pSection;
- ppNext = &pSection->pNext;
-
- /* Decode the section. */
- /** @todo copy the preamble as well. */
- rc = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin,
- (void **)&pSection->pbData, &pSection->cbData);
- if (RT_FAILURE(rc))
+ pSection->pbData = NULL;
+ pSection->cbData = 0;
+ if ( rc2 == VERR_INVALID_BASE64_ENCODING
+ && (fFlags & RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR))
+ rc = -rc2;
+ else
{
- pSection->pbData = NULL;
- pSection->cbData = 0;
+ rc = rc2;
break;
}
+ }
- /* More sections? */
- if ( offResume + 12 >= cbContent
- || offResume >= cbContent
- || !rtCrPemFindMarkerSection(pbContent, cbContent, offResume, paMarkers, cMarkers,
- &pMatch, &offBegin, &offEnd, &offResume) )
- break; /* No. */
+ /* More sections? */
+ if ( offResume + 12 >= cbContent
+ || offResume >= cbContent
+ || !rtCrPemFindMarkerSection(pbContent, cbContent, offResume, paMarkers, cMarkers,
+ &pMatch, &offBegin, &offEnd, &offResume) )
+ break; /* No. */
- /* Ok, allocate a new record for it. */
- pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
- if (RT_UNLIKELY(!pSection))
- {
- rc = VERR_NO_MEMORY;
- break;
- }
- }
- if (RT_SUCCESS(rc))
+ /* Ok, allocate a new record for it. */
+ pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
+ if (RT_UNLIKELY(!pSection))
{
- RTFileReadAllFree(pbContent, cbContent);
- return rc;
+ rc = VERR_NO_MEMORY;
+ break;
}
-
- RTCrPemFreeSections(*ppSectionHead);
}
- else
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ RTCrPemFreeSections(*ppSectionHead);
+ }
+ else
+ {
+ /*
+ * No PEM section found. Return the whole file as one binary section.
+ */
+ //pSection->pNext = NULL;
+ //pSection->pMarker = NULL;
+ pSection->pbData = (uint8_t *)RTMemDup(pbContent, cbContent);
+ pSection->cbData = cbContent;
+ //pSection->pszPreamble = NULL;
+ //pSection->cchPreamble = 0;
+ if (pSection->pbData)
{
- /*
- * No PEM section found. Return the whole file as one binary section.
- */
- //pSection->pNext = NULL;
- //pSection->pMarker = NULL;
- pSection->pbData = pbContent;
- pSection->cbData = cbContent;
- //pSection->pszPreamble = NULL;
- //pSection->cchPreamble = 0;
*ppSectionHead = pSection;
return VINF_SUCCESS;
}
- }
- else
+
rc = VERR_NO_MEMORY;
- RTFileReadAllFree(pbContent, cbContent);
+ RTMemFree(pSection);
+ }
}
+ else
+ rc = VERR_NO_MEMORY;
*ppSectionHead = NULL;
return rc;
}
+
+
+RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
+ PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo)
+{
+ *ppSectionHead = NULL;
+ AssertReturn(!(fFlags & ~RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR), VERR_INVALID_FLAGS);
+
+ size_t cbContent;
+ void *pvContent;
+ int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCrPemParseContent(pvContent, cbContent, fFlags, paMarkers, cMarkers, ppSectionHead, pErrInfo);
+ RTFileReadAllFree(pvContent, cbContent);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp b/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp
new file mode 100644
index 0000000..260de32
--- /dev/null
+++ b/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp
@@ -0,0 +1,849 @@
+/* $Id: store-cert-add-basic.cpp $ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromDir.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/assert.h>
+#include <iprt/crypto/pem.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+
+#include "x509-internal.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** BEGIN CERTIFICATE / END CERTIFICATE. */
+static RTCRPEMMARKERWORD const g_aWords_Certificate[] =
+{
+ { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/** BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE. */
+static RTCRPEMMARKERWORD const g_aWords_TrustedCertificate[] =
+{
+ { RT_STR_TUPLE("TRUSTED") },
+ { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/** BEGIN X509 CERTIFICATE / END X509 CERTIFICATE. (old) */
+static RTCRPEMMARKERWORD const g_aWords_X509Certificate[] =
+{
+ { RT_STR_TUPLE("X509") },
+ { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/**
+ * X509 Certificate markers.
+ *
+ * @remark See crypto/pem/pem.h in OpenSSL for a matching list.
+ */
+static RTCRPEMMARKER const g_aX509CertificateMarkers[3] =
+{
+ { g_aWords_Certificate, RT_ELEMENTS(g_aWords_Certificate) },
+ { g_aWords_TrustedCertificate, RT_ELEMENTS(g_aWords_TrustedCertificate) },
+ { g_aWords_X509Certificate, RT_ELEMENTS(g_aWords_X509Certificate) }
+};
+
+
+
+/**
+ * Checks if we've found all the certificates already.
+ *
+ * @returns true if all found, false if not.
+ * @param afFound Indicator array.
+ * @param cWanted Number of wanted certificates.
+ */
+DECLINLINE(bool) rtCrStoreAllDone(bool const *afFound, size_t cWanted)
+{
+ while (cWanted-- > 0)
+ if (!afFound[cWanted])
+ return false;
+ return true;
+}
+
+
+/**
+ * Checks if the given certificate specs matches the given wanted poster.
+ *
+ * @returns true if match, false if not.
+ * @param pWanted The certificate wanted poster.
+ * @param cbEncoded The candidate certificate encoded size.
+ * @param paSha1 The candidate certificate SHA-1 fingerprint.
+ * @param paSha512 The candidate certificate SHA-512 fingerprint.
+ * @param pCert The decoded candidate certificate, optional. If not
+ * given the result will be uncertain.
+ */
+DECLINLINE(bool) rtCrStoreIsCertEqualToWanted(PCRTCRCERTWANTED pWanted,
+ size_t cbEncoded,
+ uint8_t const pabSha1[RTSHA1_HASH_SIZE],
+ uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+ PCRTCRX509CERTIFICATE pCert)
+{
+ if ( pWanted->cbEncoded != cbEncoded
+ && pWanted->cbEncoded != 0)
+ return false;
+
+ if ( pWanted->fSha1Fingerprint
+ && memcmp(pWanted->abSha1, pabSha1, RTSHA1_HASH_SIZE) != 0)
+ return false;
+
+ if ( pWanted->fSha512Fingerprint
+ && memcmp(pWanted->abSha512, pabSha512, RTSHA512_HASH_SIZE) != 0)
+ return false;
+
+ if ( pWanted->pszSubject
+ && pCert
+ && !RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, pWanted->pszSubject))
+ return false;
+
+ return true;
+}
+
+
+/**
+ * Checks if a certificate is wanted.
+ *
+ * @returns true if match, false if not.
+ * @param paWanted The certificate wanted posters.
+ * @param cWanted The number of wanted posters.
+ * @param apfFound Found initicators running paralell to @a paWanted.
+ * @param cbEncoded The candidate certificate encoded size.
+ * @param paSha1 The candidate certificate SHA-1 fingerprint.
+ * @param paSha512 The candidate certificate SHA-512 fingerprint.
+ * @param pCert The decoded candidate certificate, optional. If not
+ * given the result will be uncertain.
+ */
+DECLINLINE(bool) rtCrStoreIsCertWanted(PCRTCRCERTWANTED paWanted, size_t cWanted, bool const *pafFound, size_t cbEncoded,
+ uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+ PCRTCRX509CERTIFICATE pCert)
+{
+ for (size_t iCert = 0; iCert < cWanted; iCert++)
+ if (!pafFound[iCert])
+ if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
+ return true;
+ return false;
+}
+
+
+/**
+ * Marks a certificate as found after it has been added to the store.
+ *
+ * May actually mark several certificates as found if there are duplicates or
+ * ambiguities in the wanted list.
+ *
+ * @returns true if all have been found, false if more to search for.
+ *
+ * @param apfFound Found initicators running paralell to @a paWanted.
+ * This is what this function updates.
+ * @param paWanted The certificate wanted posters.
+ * @param cWanted The number of wanted posters.
+ * @param cbEncoded The candidate certificate encoded size.
+ * @param paSha1 The candidate certificate SHA-1 fingerprint.
+ * @param paSha512 The candidate certificate SHA-512 fingerprint.
+ * @param pCert The decoded candidate certificate, optional. If not
+ * given the result will be uncertain.
+ */
+static bool rtCrStoreMarkCertFound(bool *pafFound, PCRTCRCERTWANTED paWanted, size_t cWanted, size_t cbEncoded,
+ uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+ PCRTCRX509CERTIFICATE pCert)
+{
+ size_t cFound = 0;
+ for (size_t iCert = 0; iCert < cWanted; iCert++)
+ if (pafFound[iCert])
+ cFound++;
+ else if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
+ {
+ pafFound[iCert] = true;
+ cFound++;
+ }
+ return cFound == cWanted;
+}
+
+
+RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc)
+{
+ /*
+ * Validate input.
+ */
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+
+ /*
+ * Enumerate all the certificates in the source store, adding them to the destination.
+ */
+ RTCRSTORECERTSEARCH Search;
+ int rc = RTCrStoreCertFindAll(hStoreSrc, &Search);
+ if (RT_SUCCESS(rc))
+ {
+ PCRTCRCERTCTX pCertCtx;
+ while ((pCertCtx = RTCrStoreCertSearchNext(hStoreSrc, &Search)) != NULL)
+ {
+ int rc2 = RTCrStoreCertAddEncoded(hStore, pCertCtx->fFlags | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+ pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ break;
+ }
+ RTCrCertCtxRelease(pCertCtx);
+ }
+
+ int rc2 = RTCrStoreCertSearchDestroy(hStoreSrc, &Search); AssertRC(rc2);
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromStore);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
+{
+ /*
+ * Validate input a little.
+ */
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+ fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+ AssertReturn(cWanted, VERR_NOT_FOUND);
+ for (uint32_t i = 0; i < cWanted; i++)
+ {
+ AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+ AssertReturn( paWanted[i].pszSubject
+ || paWanted[i].fSha1Fingerprint
+ || paWanted[i].fSha512Fingerprint,
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Make sure we've got a result array.
+ */
+ bool *pafFoundFree = NULL;
+ if (!pafFound)
+ {
+ pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+ AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+ }
+
+ /*
+ * Enumerate the store entries.
+ */
+ RTCRSTORECERTSEARCH Search;
+ int rc = RTCrStoreCertFindAll(hSrcStore, &Search);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VWRN_NOT_FOUND;
+ PCRTCRCERTCTX pCertCtx;
+ while ((pCertCtx = RTCrStoreCertSearchNext(hSrcStore, &Search)) != NULL)
+ {
+ if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+ && pCertCtx->cbEncoded > 0
+ && pCertCtx->pCert)
+ {
+ /*
+ * If the certificate is wanted, try add it to the store.
+ */
+ uint8_t abSha1[RTSHA1_HASH_SIZE];
+ RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
+ uint8_t abSha512[RTSHA512_HASH_SIZE];
+ RTSha512(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
+ if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+ {
+ int rc2 = RTCrStoreCertAddEncoded(hStore,
+ RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+ pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL /*pErrInfo*/);
+ if (RT_SUCCESS(rc2))
+ {
+ /*
+ * Mark it as found, stop if we've found all.
+ */
+ if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
+ pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+ {
+ if (RT_SUCCESS(rc))
+ rc = VINF_SUCCESS;
+ RTCrCertCtxRelease(pCertCtx);
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Some error adding the certificate. Since it cannot be anything with
+ * the encoding, it must be something with the store or resources, so
+ * always return the error status.
+ */
+ rc = rc2;
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ {
+ RTCrCertCtxRelease(pCertCtx);
+ break;
+ }
+ }
+ }
+ }
+ RTCrCertCtxRelease(pCertCtx);
+ }
+ int rc2 = RTCrStoreCertSearchDestroy(hSrcStore, &Search);
+ AssertRC(rc2);
+ }
+
+ if (pafFoundFree)
+ RTMemTmpFree(pafFoundFree);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
+
+
+RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
+{
+ /*
+ * Validate input a little.
+ */
+ AssertReturn(cWanted, VERR_NOT_FOUND);
+ for (uint32_t i = 0; i < cWanted; i++)
+ {
+ AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+ AssertReturn( paWanted[i].pszSubject
+ || paWanted[i].fSha1Fingerprint
+ || paWanted[i].fSha512Fingerprint,
+ VERR_INVALID_PARAMETER);
+ }
+ AssertPtrReturn(pafFound, VERR_INVALID_POINTER);
+
+ /*
+ * Clear the found array.
+ */
+ for (uint32_t iCert = 0; iCert < cWanted; iCert++)
+ pafFound[iCert] = false;
+
+ /*
+ * Enumerate the store entries.
+ */
+ RTCRSTORECERTSEARCH Search;
+ int rc = RTCrStoreCertFindAll(hStore, &Search);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VWRN_NOT_FOUND;
+ PCRTCRCERTCTX pCertCtx;
+ while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
+ {
+ if ( (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+ && pCertCtx->cbEncoded > 0
+ && pCertCtx->pCert)
+ {
+ /*
+ * Hash it and check if it's wanted. Stop when we've found all.
+ */
+ uint8_t abSha1[RTSHA1_HASH_SIZE];
+ RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
+ uint8_t abSha512[RTSHA512_HASH_SIZE];
+ RTSha512(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
+ if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+ {
+ rc = VINF_SUCCESS;
+ RTCrCertCtxRelease(pCertCtx);
+ break;
+ }
+ }
+ RTCrCertCtxRelease(pCertCtx);
+ }
+ int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search);
+ AssertRC(rc2);
+ }
+
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
+
+
+RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
+{
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+
+ size_t cbContent;
+ void *pvContent;
+ int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Is it a java key store file?
+ */
+ if ( cbContent > 32
+ && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
+ && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
+ rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
+ /*
+ * No assume PEM or DER encoded binary certificate.
+ */
+ else
+ {
+ PCRTCRPEMSECTION pSectionHead;
+ rc = RTCrPemParseContent(pvContent, cbContent,
+ (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
+ ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
+ g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
+ &pSectionHead, pErrInfo);
+ if (RT_SUCCESS(rc))
+ {
+ PCRTCRPEMSECTION pCurSec = pSectionHead;
+ while (pCurSec)
+ {
+ int rc2 = RTCrStoreCertAddEncoded(hStore,
+ RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+ pCurSec->pbData, pCurSec->cbData,
+ !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ {
+ rc = rc2;
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ break;
+ }
+ pCurSec = pCurSec->pNext;
+ }
+
+ RTCrPemFreeSections(pSectionHead);
+ }
+ }
+ RTFileReadAllFree(pvContent, cbContent);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromFile);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
+{
+ /*
+ * Validate input a little.
+ */
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+ fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+ AssertReturn(cWanted, VERR_NOT_FOUND);
+ for (uint32_t i = 0; i < cWanted; i++)
+ {
+ AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+ AssertReturn( paWanted[i].pszSubject
+ || paWanted[i].fSha1Fingerprint
+ || paWanted[i].fSha512Fingerprint,
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Make sure we've got a result array.
+ */
+ bool *pafFoundFree = NULL;
+ if (!pafFound)
+ {
+ pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+ AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+ }
+
+ size_t cbContent;
+ void *pvContent;
+ int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Is it a java key store file? If so, load it into a tmp store
+ * which we can search. Don't want to duplicate the JKS reader code.
+ */
+ if ( cbContent > 32
+ && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
+ && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
+ {
+ RTCRSTORE hTmpStore;
+ rc = RTCrStoreCreateInMem(&hTmpStore, 64);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
+ if (RT_SUCCESS(rc))
+ rc = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
+ RTCrStoreRelease(hTmpStore);
+ }
+ else
+ rc = RTErrInfoSet(pErrInfo, rc, "Error creating temporary crypto store");
+ }
+ /*
+ * No assume PEM or DER encoded binary certificate. Inspect them one by one.
+ */
+ else
+ {
+ PCRTCRPEMSECTION pSectionHead;
+ rc = RTCrPemParseContent(pvContent, cbContent,
+ (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
+ ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
+ g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
+ &pSectionHead, pErrInfo);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VWRN_NOT_FOUND;
+ for (PCRTCRPEMSECTION pCurSec = pSectionHead; pCurSec; pCurSec = pCurSec->pNext)
+ {
+ if (!pCurSec->cbData)
+ continue;
+
+ /*
+ * See if this is a binary blob we might be interested in.
+ */
+ uint8_t abSha1[RTSHA1_HASH_SIZE];
+ RTSha1(pCurSec->pbData, pCurSec->cbData, abSha1);
+ uint8_t abSha512[RTSHA512_HASH_SIZE];
+ RTSha512(pCurSec->pbData, pCurSec->cbData, abSha512);
+ if (!rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, NULL))
+ continue;
+
+ /*
+ * Decode the certificate so we can match the subject string.
+ */
+ RTASN1CURSORPRIMARY Cursor;
+ RTAsn1CursorInitPrimary(&Cursor, pCurSec->pbData, (uint32_t)pCurSec->cbData,
+ !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL,
+ &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "InMem");
+ RTCRX509CERTIFICATE X509Cert;
+ int rc2 = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &X509Cert, "Cert");
+ if (RT_SUCCESS(rc2))
+ {
+ rc2 = RTCrX509Certificate_CheckSanity(&X509Cert, 0, !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL, "Cert");
+ if (RT_SUCCESS(rc2))
+ {
+ if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, &X509Cert))
+ {
+ /*
+ * The certificate is wanted, now add it to the store.
+ */
+ rc2 = RTCrStoreCertAddEncoded(hStore,
+ RTCRCERTCTX_F_ENC_X509_DER
+ | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+ pCurSec->pbData, pCurSec->cbData,
+ !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
+ if (RT_SUCCESS(rc2))
+ {
+ /*
+ * Mark it as found, stop if we've found all.
+ */
+ if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
+ pCurSec->cbData, abSha1, abSha512, &X509Cert))
+ {
+ RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
+ rc = VINF_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+ else
+ Assert(!pErrInfo || RTErrInfoIsSet(pErrInfo));
+ RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
+ }
+ else if (!RTErrInfoIsSet(pErrInfo))
+ RTErrInfoSetF(pErrInfo, rc2, "RTCrX509Certificate_DecodeAsn1 failed");
+
+ /*
+ * Stop on error, if requested. Otherwise, let pErrInfo keep it.
+ */
+ if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ {
+ rc = rc2;
+ break;
+ }
+ } /* For each PEM section. */
+
+ RTCrPemFreeSections(pSectionHead);
+ }
+ }
+ RTFileReadAllFree(pvContent, cbContent);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+
+ if (pafFoundFree)
+ RTMemTmpFree(pafFoundFree);
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFile);
+
+
+/**
+ * Checks if the directory entry matches the specified suffixes.
+ *
+ * @returns true on match, false on mismatch.
+ * @param pDirEntry The directory to check.
+ * @param paSuffixes The array of suffixes to match against.
+ * @param cSuffixes The number of suffixes in the array.
+ */
+DECLINLINE(bool) rtCrStoreIsSuffixMatch(PCRTDIRENTRY pDirEntry, PCRTSTRTUPLE paSuffixes, size_t cSuffixes)
+{
+ if (cSuffixes == 0)
+ return true;
+
+ size_t const cchName = pDirEntry->cbName;
+ size_t i = cSuffixes;
+ while (i-- > 0)
+ if ( cchName > paSuffixes[i].cch
+ && memcmp(&pDirEntry->szName[cchName - paSuffixes[i].cch], paSuffixes[i].psz, paSuffixes[i].cch) == 0)
+ return true;
+
+ return false;
+}
+
+
+RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir,
+ PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo)
+{
+ /*
+ * Validate input.
+ */
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+ size_t i = cSuffixes;
+ while (i-- > 0)
+ {
+ Assert(paSuffixes[i].cch > 0);
+ Assert(strlen(paSuffixes[i].psz) == paSuffixes[i].cch);
+ }
+
+ /*
+ * Prepare for constructing path to the files in the directory, so that we
+ * can open them.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
+ if (cchPath > 0)
+ {
+ size_t const cbMaxFilename = sizeof(szPath) - cchPath;
+
+ /*
+ * Enumerate the directory.
+ */
+ PRTDIR hDir;
+ rc = RTDirOpen(&hDir, pszDir);
+ if (RT_SUCCESS(rc))
+ {
+ for (;;)
+ {
+ /* Read the next entry. */
+ union
+ {
+ RTDIRENTRY DirEntry;
+ uint8_t abPadding[RTPATH_MAX + sizeof(RTDIRENTRY)];
+ } u;
+ size_t cbBuf = sizeof(u);
+ int rc2 = RTDirRead(hDir, &u.DirEntry, &cbBuf);
+ if (RT_SUCCESS(rc2))
+ {
+ if ( ( u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
+ || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
+ || ( u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
+ && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
+ && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
+ {
+ if (u.DirEntry.cbName < cbMaxFilename)
+ {
+ memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName + 1);
+ rc2 = RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
+ if ( RT_SUCCESS(rc2)
+ && u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
+ {
+ /*
+ * Add it.
+ */
+ rc2 = RTCrStoreCertAddFromFile(hStore, fFlags, szPath, pErrInfo);
+ if (RT_FAILURE(rc2))
+ {
+ rc = rc2;
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ break;
+ }
+ }
+ }
+ else
+ {
+ rc = RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
+ " Too long filename (%u bytes)", u.DirEntry.cbName);
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (rc2 != VERR_NO_MORE_FILES)
+ rc = RTErrInfoAddF(pErrInfo, rc2, " RTDirRead failed: %Rrc", rc2);
+ break;
+ }
+ }
+
+ RTDirClose(hDir);
+ }
+ else
+ rc = RTErrInfoAddF(pErrInfo, rc, " RTDirOpen('%s'): %Rrc", pszDir, rc);
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromDir);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
+ const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
+ PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
+{
+ /*
+ * Validate input a little.
+ */
+ AssertReturn(*pszDir, VERR_PATH_ZERO_LENGTH);
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+ fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+ AssertReturn(cWanted, VERR_NOT_FOUND);
+ for (uint32_t i = 0; i < cWanted; i++)
+ {
+ AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+ AssertReturn( paWanted[i].pszSubject
+ || paWanted[i].fSha1Fingerprint
+ || paWanted[i].fSha512Fingerprint,
+ VERR_INVALID_PARAMETER);
+ }
+
+ /*
+ * Prepare for constructing path to the files in the directory, so that we
+ * can open them.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
+ if (RT_SUCCESS(rc))
+ {
+ size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
+ if (cchPath > 0)
+ {
+ size_t const cbMaxFilename = sizeof(szPath) - cchPath;
+
+ /*
+ * Enumerate the directory.
+ */
+ PRTDIR hDir;
+ rc = RTDirOpen(&hDir, pszDir);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VWRN_NOT_FOUND;
+ for (;;)
+ {
+ /* Read the next entry. */
+ union
+ {
+ RTDIRENTRY DirEntry;
+ uint8_t abPadding[RTPATH_MAX + sizeof(RTDIRENTRY)];
+ } u;
+ size_t cbEntry = sizeof(u);
+ int rc2 = RTDirRead(hDir, &u.DirEntry, &cbEntry);
+ if (RT_SUCCESS(rc2))
+ {
+ if ( ( u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
+ || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
+ || ( u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
+ && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
+ && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
+ {
+ if (u.DirEntry.cbName < cbMaxFilename)
+ {
+ memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName);
+ szPath[cchPath + u.DirEntry.cbName] = '\0';
+ if (u.DirEntry.enmType != RTDIRENTRYTYPE_FILE)
+ RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
+ if (u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
+ {
+ rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, szPath,
+ paWanted, cWanted, pafFound, pErrInfo);
+ if (rc2 == VINF_SUCCESS)
+ {
+ Assert(rtCrStoreAllDone(pafFound, cWanted));
+ if (RT_SUCCESS(rc))
+ rc = VINF_SUCCESS;
+ break;
+ }
+ if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ {
+ rc = rc2;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * pErrInfo keeps the status code unless it's fatal.
+ */
+ RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
+ " Too long filename (%u bytes)", u.DirEntry.cbName);
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ {
+ rc = VERR_FILENAME_TOO_LONG;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (rc2 != VERR_NO_MORE_FILES)
+ {
+ RTErrInfoAddF(pErrInfo, rc2, "RTDirRead failed: %Rrc", rc2);
+ if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+ rc = rc2;
+ }
+ break;
+ }
+ }
+ RTDirClose(hDir);
+ }
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+ }
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromDir);
+
diff --git a/src/VBox/Runtime/common/crypto/store-inmem.cpp b/src/VBox/Runtime/common/crypto/store-inmem.cpp
index 53d0e15..5b83935 100644
--- a/src/VBox/Runtime/common/crypto/store-inmem.cpp
+++ b/src/VBox/Runtime/common/crypto/store-inmem.cpp
@@ -281,18 +281,40 @@ static DECLCALLBACK(int) rtCrStoreInMem_CertAddEncoded(void *pvProvider, uint32_
PRTCRSTOREINMEM pThis = (PRTCRSTOREINMEM)pvProvider;
int rc;
- AssertMsgReturn( fFlags == RTCRCERTCTX_F_ENC_X509_DER
- || fFlags == RTCRCERTCTX_F_ENC_TAF_DER
+ AssertMsgReturn( (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+ || (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_TAF_DER
, ("Only X.509 and TAF DER are supported: %#x\n", fFlags), VERR_INVALID_FLAGS);
- if (pThis->cCerts + 1 > pThis->cCertsAlloc)
+ /*
+ * Check for duplicates if specified.
+ */
+ if (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND)
+ {
+ uint32_t iCert = pThis->cCerts;
+ while (iCert-- > 0)
+ {
+ PRTCRSTOREINMEMCERT pCert = pThis->papCerts[iCert];
+ if ( pCert->Core.Public.cbEncoded == cbEncoded
+ && pCert->Core.Public.fFlags == (fFlags & RTCRCERTCTX_F_ENC_MASK)
+ && memcmp(pCert->Core.Public.pabEncoded, pbEncoded, cbEncoded) == 0)
+ return VWRN_ALREADY_EXISTS;
+ }
+ }
+
+ /*
+ * Add it.
+ */
+ if (pThis->cCerts + 1 <= pThis->cCertsAlloc)
+ { /* likely */ }
+ else
{
rc = rtCrStoreInMemGrow(pThis, pThis->cCerts + 1);
if (RT_FAILURE(rc))
return rc;
}
- rc = rtCrStoreInMemCreateCertEntry(pThis, fFlags, pbEncoded, cbEncoded, pErrInfo, &pThis->papCerts[pThis->cCerts]);
+ rc = rtCrStoreInMemCreateCertEntry(pThis, fFlags & RTCRCERTCTX_F_ENC_MASK, pbEncoded, cbEncoded,
+ pErrInfo, &pThis->papCerts[pThis->cCerts]);
if (RT_SUCCESS(rc))
{
pThis->cCerts++;
@@ -359,4 +381,5 @@ RTDECL(int) RTCrStoreCreateInMem(PRTCRSTORE phStore, uint32_t cSizeHint)
}
return rc;
}
+RT_EXPORT_SYMBOL(RTCrStoreCreateInMem);
diff --git a/src/VBox/Runtime/common/crypto/store-internal.h b/src/VBox/Runtime/common/crypto/store-internal.h
index d0e35f3..bb636b2 100644
--- a/src/VBox/Runtime/common/crypto/store-internal.h
+++ b/src/VBox/Runtime/common/crypto/store-internal.h
@@ -124,6 +124,9 @@ typedef struct RTCRSTOREPROVIDER
/**
* Adds a certificate to the store.
*
+ * @returns IPRT status.
+ * @retval VWRN_ALREADY_EXISTS if the certificate is already present and
+ * RTCRCERTCTX_F_ADD_IF_NOT_FOUND was specified.
* @param pvProvider The provider specific data.
* @param fFlags RTCRCERTCTX_F_XXX.
* @param pbEncoded The encoded certificate bytes.
diff --git a/src/VBox/Runtime/common/crypto/store.cpp b/src/VBox/Runtime/common/crypto/store.cpp
index b4e1edb..36e32c0 100644
--- a/src/VBox/Runtime/common/crypto/store.cpp
+++ b/src/VBox/Runtime/common/crypto/store.cpp
@@ -173,8 +173,9 @@ RTDECL(int) RTCrStoreCertAddEncoded(RTCRSTORE hStore, uint32_t fFlags, void cons
AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, VERR_INVALID_HANDLE);
AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
AssertReturn(cbSrc > 16 && cbSrc < _1M, VERR_OUT_OF_RANGE);
- AssertMsgReturn( fFlags == RTCRCERTCTX_F_ENC_X509_DER
- || fFlags == RTCRCERTCTX_F_ENC_TAF_DER
+ AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ENC_MASK)), VERR_INVALID_FLAGS);
+ AssertMsgReturn( (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+ || (fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_TAF_DER
, ("Only X.509 and TAF DER supported: %#x\n", fFlags), VERR_INVALID_FLAGS);
int rc;
@@ -286,6 +287,29 @@ RTDECL(int) RTCrStoreCertSearchDestroy(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pS
+RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore)
+{
+ PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
+ AssertPtrReturn(pThis, UINT32_MAX);
+ AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
+
+ RTCRSTORECERTSEARCH Search;
+ int rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
+ AssertRCReturn(rc, UINT32_MAX);
+
+
+ uint32_t cCerts = 0;
+ PCRTCRCERTCTX pCur;
+ while ((pCur = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search)) != NULL)
+ {
+ RTCrCertCtxRelease(pCur);
+ cCerts++;
+ }
+
+ return cCerts;
+}
+
+
#ifdef IPRT_WITH_OPENSSL
/*
* OpenSSL helper.
diff --git a/src/VBox/Runtime/common/crypto/tsp-template.h b/src/VBox/Runtime/common/crypto/tsp-template.h
index 8499f3c..6ca057a 100644
--- a/src/VBox/Runtime/common/crypto/tsp-template.h
+++ b/src/VBox/Runtime/common/crypto/tsp-template.h
@@ -59,15 +59,15 @@ RTASN1TMPL_END_SEQCORE();
#define RTASN1TMPL_EXT_NAME RTCrTspAccuracy
#define RTASN1TMPL_INT_NAME rtCrTspAccuracy
RTASN1TMPL_BEGIN_SEQCORE();
-RTASN1TMPL_MEMBER_EX( Seconds, RTASN1INTEGER, RTAsn1Integer,
- RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(Millis, 1, UINT64_MAX, RT_NOTHING));
+RTASN1TMPL_MEMBER_OPT_ITAG_EX( Seconds, RTASN1INTEGER, RTAsn1Integer, ASN1_TAG_INTEGER, RTASN1TMPL_ITAG_F_UP,
+ RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(Seconds, 0, UINT64_MAX, RT_NOTHING));
/** @todo The Millis and Micros fields makes no sense if Seconds > 1, while the
* Micros field makes no sense with Millis > 1. Add constraints
* expressing this dependency. */
RTASN1TMPL_MEMBER_OPT_ITAG_EX( Millis, RTASN1INTEGER, RTAsn1Integer, 0, RTASN1TMPL_ITAG_F_CP,
RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(Millis, 1, 999, RT_NOTHING));
RTASN1TMPL_MEMBER_OPT_ITAG_EX( Micros, RTASN1INTEGER, RTAsn1Integer, 1, RTASN1TMPL_ITAG_F_CP,
- RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(Millis, 1, 999, RT_NOTHING));
+ RTASN1TMPL_MEMBER_CONSTR_U64_MIN_MAX(Micros, 1, 999, RT_NOTHING));
RTASN1TMPL_END_SEQCORE();
#undef RTASN1TMPL_TYPE
#undef RTASN1TMPL_EXT_NAME
diff --git a/src/VBox/Runtime/common/crypto/x509-core.cpp b/src/VBox/Runtime/common/crypto/x509-core.cpp
index 3b5c511..86b8212 100644
--- a/src/VBox/Runtime/common/crypto/x509-core.cpp
+++ b/src/VBox/Runtime/common/crypto/x509-core.cpp
@@ -1250,7 +1250,8 @@ RTDECL(bool) RTCrX509GeneralSubtree_ConstraintMatch(PCRTCRX509GENERALSUBTREE pCo
static void rtCrx509TbsCertificate_AddKeyUsageFlags(PRTCRX509TBSCERTIFICATE pThis, PCRTCRX509EXTENSION pExtension)
{
AssertReturnVoid(pExtension->enmValue == RTCRX509EXTENSIONVALUE_BIT_STRING);
- AssertReturnVoid(pExtension->ExtnValue.pEncapsulated->cb <= 2);
+ /* 3 = 1 byte for unused bit count, followed by one or two bytes containing actual bits. RFC-5280 defines bits 0 thru 8. */
+ AssertReturnVoid(pExtension->ExtnValue.pEncapsulated->cb <= 3);
pThis->T3.fKeyUsage |= (uint32_t)RTAsn1BitString_GetAsUInt64((PCRTASN1BITSTRING)pExtension->ExtnValue.pEncapsulated);
}
diff --git a/src/VBox/Runtime/common/ldr/ldrPE.cpp b/src/VBox/Runtime/common/ldr/ldrPE.cpp
index 5583958..759bdcb 100644
--- a/src/VBox/Runtime/common/ldr/ldrPE.cpp
+++ b/src/VBox/Runtime/common/ldr/ldrPE.cpp
@@ -3480,7 +3480,7 @@ static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const
Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the ATI kludge\n",
pszLogName, u.Cfg64.Size, Dir.Size));
Dir.Size = u.Cfg64.Size;
- memset(&u.Cfg64, 0, sizeof(u.Cfg64));
+ RT_ZERO(u.Cfg64);
rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
if (RT_FAILURE(rc))
return rc;
@@ -3490,7 +3490,21 @@ static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const
/* Kludge #2, ntdll.dll from XP seen with Dir.Size=0x40 and Cfg64.Size=0x00. */
if (Dir.Size == 0x40 && u.Cfg64.Size == 0x00 && !pModPe->f64Bit)
{
+ Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the XP kludge\n",
+ pszLogName, u.Cfg64.Size, Dir.Size));
u.Cfg64.Size = 0x40;
+ }
+
+ /* Kludge #3, imagehlp.dll from W10/32 seen with Dir.Size=0x40 (V1) and Cfg64.Size=0x68 (V3). */
+ if (Dir.Size == 0x40 && u.Cfg64.Size == 0x68 && !pModPe->f64Bit)
+ {
+ Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the W10/32 kludge\n",
+ pszLogName, u.Cfg64.Size, Dir.Size));
+ Dir.Size = u.Cfg64.Size;
+ RT_ZERO(u.Cfg64);
+ rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
+ if (RT_FAILURE(rc))
+ return rc;
rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
}
@@ -3600,11 +3614,10 @@ static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const
} while (off < Dir.Size);
}
RTMemTmpFree(pFirst);
- if (RT_FAILURE(rc))
+ if (RT_FAILURE(rc) && !(fFlags & RTLDR_O_FOR_DEBUG))
return rc;
}
-
return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/common/misc/http.cpp b/src/VBox/Runtime/common/misc/http.cpp
deleted file mode 100644
index 6c8e294..0000000
--- a/src/VBox/Runtime/common/misc/http.cpp
+++ /dev/null
@@ -1,601 +0,0 @@
-/* $Id: http.cpp $ */
-/** @file
- * IPRT - HTTP communication API.
- */
-
-/*
- * Copyright (C) 2012-2013 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include <iprt/http.h>
-#include "internal/iprt.h"
-
-#include <iprt/assert.h>
-#include <iprt/env.h>
-#include <iprt/err.h>
-#include <iprt/mem.h>
-#include <iprt/string.h>
-#include <iprt/file.h>
-#include <iprt/stream.h>
-
-#include <curl/curl.h>
-#include <openssl/ssl.h>
-#include "internal/magics.h"
-
-
-/*******************************************************************************
-* Structures and Typedefs *
-*******************************************************************************/
-typedef struct RTHTTPINTERNAL
-{
- /** Magic value. */
- uint32_t u32Magic;
- /** cURL handle. */
- CURL *pCurl;
- /** The last response code. */
- long lLastResp;
- /** custom headers */
- struct curl_slist *pHeaders;
- /** CA certificate for HTTPS authentication check. */
- char *pcszCAFile;
- /** Abort the current HTTP request if true. */
- bool fAbort;
- /** The location field for 301 responses. */
- char *pszRedirLocation;
-} RTHTTPINTERNAL;
-typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
-
-typedef struct RTHTTPMEMCHUNK
-{
- uint8_t *pu8Mem;
- size_t cb;
-} RTHTTPMEMCHUNK;
-typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
-
-/*******************************************************************************
-* Defined Constants And Macros *
-*******************************************************************************/
-#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
-
-/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
-#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
- do { \
- AssertPtrReturn((hHttp), (rcCurl)); \
- AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
- } while (0)
-
-/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
-#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
-
-/** Validates a handle and returns (void) if not valid. */
-#define RTHTTP_VALID_RETURN_VOID(hHttp) \
- do { \
- AssertPtrReturnVoid(hHttp); \
- AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
- } while (0)
-
-
-RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
-{
- AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
-
- CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
- if (CURL_FAILED(rcCurl))
- return VERR_HTTP_INIT_FAILED;
-
- CURL *pCurl = curl_easy_init();
- if (!pCurl)
- return VERR_HTTP_INIT_FAILED;
-
- PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
- if (!pHttpInt)
- return VERR_NO_MEMORY;
-
- pHttpInt->u32Magic = RTHTTP_MAGIC;
- pHttpInt->pCurl = pCurl;
-
- *phHttp = (RTHTTP)pHttpInt;
-
- return VINF_SUCCESS;
-}
-
-RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
-{
- if (!hHttp)
- return;
-
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN_VOID(pHttpInt);
-
- pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
-
- curl_easy_cleanup(pHttpInt->pCurl);
-
- if (pHttpInt->pHeaders)
- curl_slist_free_all(pHttpInt->pHeaders);
-
- if (pHttpInt->pcszCAFile)
- RTStrFree(pHttpInt->pcszCAFile);
-
- if (pHttpInt->pszRedirLocation)
- RTStrFree(pHttpInt->pszRedirLocation);
-
- RTMemFree(pHttpInt);
-
- curl_global_cleanup();
-}
-
-static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
-{
- PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
- size_t cbAll = cb * n;
-
- pMem->pu8Mem = (uint8_t*)RTMemRealloc(pMem->pu8Mem, pMem->cb + cbAll + 1);
- if (pMem->pu8Mem)
- {
- memcpy(&pMem->pu8Mem[pMem->cb], pvBuf, cbAll);
- pMem->cb += cbAll;
- pMem->pu8Mem[pMem->cb] = '\0';
- }
- return cbAll;
-}
-
-static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow,
- double UlTotal, double UlNow)
-{
- PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData;
- AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1);
-
- return pHttpInt->fAbort ? 1 : 0;
-}
-
-RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- pHttpInt->fAbort = true;
-
- return VINF_SUCCESS;
-}
-
-RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- if (!pHttpInt->pszRedirLocation)
- return VERR_HTTP_NOT_FOUND;
-
- *ppszRedirLocation = RTStrDup(pHttpInt->pszRedirLocation);
- return VINF_SUCCESS;
-}
-
-RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- /*
- * Very limited right now, just enought to make it work for ourselves.
- */
- char szProxy[_1K];
- int rc = RTEnvGetEx(RTENV_DEFAULT, "http_proxy", szProxy, sizeof(szProxy), NULL);
- if (RT_SUCCESS(rc))
- {
- int rcCurl;
- if (!strncmp(szProxy, RT_STR_TUPLE("http://")))
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
- }
- else
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
- }
- }
- else if (rc == VERR_ENV_VAR_NOT_FOUND)
- rc = VINF_SUCCESS;
-
- return rc;
-}
-
-RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
- const char *pcszProxyUser, const char *pcszProxyPwd)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
- AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
-
- int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
- if (uPort != 0)
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
- }
-
- if (pcszProxyUser && pcszProxyPwd)
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
- }
-
- return VINF_SUCCESS;
-}
-
-RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- if (!cHeaders)
- {
- if (pHttpInt->pHeaders)
- curl_slist_free_all(pHttpInt->pHeaders);
- pHttpInt->pHeaders = 0;
- return VINF_SUCCESS;
- }
-
- struct curl_slist *pHeaders = NULL;
- for (size_t i = 0; i < cHeaders; i++)
- pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
-
- pHttpInt->pHeaders = pHeaders;
- int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
- return VINF_SUCCESS;
-}
-
-RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert,
- uint8_t **pabSha1, size_t *pcbSha1,
- uint8_t **pabSha512, size_t *pcbSha512)
-{
- int rc = VINF_SUCCESS;
-
- BIO *cert = BIO_new_mem_buf(pcszCert, (int)cbCert);
- if (cert)
- {
- X509 *crt = NULL;
- if (PEM_read_bio_X509(cert, &crt, NULL, NULL))
- {
- unsigned cb;
- unsigned char md[EVP_MAX_MD_SIZE];
-
- int rc1 = X509_digest(crt, EVP_sha1(), md, &cb);
- if (rc1 > 0)
- {
- *pabSha1 = (uint8_t*)RTMemAlloc(cb);
- if (*pabSha1)
- {
- memcpy(*pabSha1, md, cb);
- *pcbSha1 = cb;
-
- rc1 = X509_digest(crt, EVP_sha512(), md, &cb);
- if (rc1 > 0)
- {
- *pabSha512 = (uint8_t*)RTMemAlloc(cb);
- if (*pabSha512)
- {
- memcpy(*pabSha512, md, cb);
- *pcbSha512 = cb;
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
-
- if (RT_FAILURE(rc))
- RTMemFree(*pabSha1);
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- X509_free(crt);
- }
- else
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- BIO_free(cert);
- }
- else
- rc = VERR_INTERNAL_ERROR;
-
- return rc;
-}
-
-RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- if (pHttpInt->pcszCAFile)
- RTStrFree(pHttpInt->pcszCAFile);
- pHttpInt->pcszCAFile = RTStrDup(pcszCAFile);
- if (!pHttpInt->pcszCAFile)
- return VERR_NO_MEMORY;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Figures out the IPRT status code for a GET.
- *
- * @returns IPRT status code.
- * @param pHttpInt HTTP instance.
- * @param rcCurl What curl returned.
- */
-static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl)
-{
- int rc = VERR_INTERNAL_ERROR;
-
- if (pHttpInt->pszRedirLocation)
- {
- RTStrFree(pHttpInt->pszRedirLocation);
- pHttpInt->pszRedirLocation = NULL;
- }
- if (rcCurl == CURLE_OK)
- {
- curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
- switch (pHttpInt->lLastResp)
- {
- case 200:
- /* OK, request was fulfilled */
- case 204:
- /* empty response */
- rc = VINF_SUCCESS;
- break;
- case 301:
- {
- const char *pszRedirect;
- curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
- size_t cb = strlen(pszRedirect);
- if (cb > 0 && cb < 2048)
- pHttpInt->pszRedirLocation = RTStrDup(pszRedirect);
- rc = VERR_HTTP_REDIRECTED;
- break;
- }
- case 400:
- /* bad request */
- rc = VERR_HTTP_BAD_REQUEST;
- break;
- case 403:
- /* forbidden, authorization will not help */
- rc = VERR_HTTP_ACCESS_DENIED;
- break;
- case 404:
- /* URL not found */
- rc = VERR_HTTP_NOT_FOUND;
- break;
- }
- }
- else
- {
- switch (rcCurl)
- {
- case CURLE_URL_MALFORMAT:
- case CURLE_COULDNT_RESOLVE_HOST:
- rc = VERR_HTTP_NOT_FOUND;
- break;
- case CURLE_COULDNT_CONNECT:
- rc = VERR_HTTP_COULDNT_CONNECT;
- break;
- case CURLE_SSL_CONNECT_ERROR:
- rc = VERR_HTTP_SSL_CONNECT_ERROR;
- break;
- case CURLE_SSL_CACERT:
- /* The peer certificate cannot be authenticated with the CA certificates
- * set by RTHttpSetCAFile(). We need other or additional CA certificates. */
- rc = VERR_HTTP_CACERT_CANNOT_AUTHENTICATE;
- break;
- case CURLE_SSL_CACERT_BADFILE:
- /* CAcert file (see RTHttpSetCAFile()) has wrong format */
- rc = VERR_HTTP_CACERT_WRONG_FORMAT;
- break;
- case CURLE_ABORTED_BY_CALLBACK:
- /* forcefully aborted */
- rc = VERR_HTTP_ABORTED;
- break;
- default:
- break;
- }
- }
-
- return rc;
-}
-
-RTR3DECL(int) rtHttpGet(RTHTTP hHttp, const char *pcszUrl, uint8_t **ppvResponse, size_t *pcb)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- pHttpInt->fAbort = false;
-
- int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
-#if 0
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-#endif
-
- const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
- if (pHttpInt->pcszCAFile)
- pcszCAFile = pHttpInt->pcszCAFile;
- if (RTFileExists(pcszCAFile))
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- }
-
- RTHTTPMEMCHUNK chunk = { NULL, 0 };
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
- rcCurl = curl_easy_perform(pHttpInt->pCurl);
- int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
- *ppvResponse = chunk.pu8Mem;
- *pcb = chunk.cb;
-
- return rc;
-}
-
-
-RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
-{
- uint8_t *pv;
- size_t cb;
- int rc = rtHttpGet(hHttp, pcszUrl, &pv, &cb);
- *ppszResponse = (char*)pv;
- return rc;
-}
-
-
-RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb)
-{
- return rtHttpGet(hHttp, pcszUrl, (uint8_t**)ppvResponse, pcb);
-}
-
-
-static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser)
-{
- size_t cbAll = cb * n;
- RTFILE hFile = (RTFILE)(intptr_t)pvUser;
-
- size_t cbWritten = 0;
- int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten);
- if (RT_SUCCESS(rc))
- return cbWritten;
- return 0;
-}
-
-
-RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
-{
- PRTHTTPINTERNAL pHttpInt = hHttp;
- RTHTTP_VALID_RETURN(pHttpInt);
-
- /*
- * Set up the request.
- */
- pHttpInt->fAbort = false;
-
- int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-
-#if 0
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
- if (CURL_FAILED(rcCurl))
- return VERR_INVALID_PARAMETER;
-#endif
-
- const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
- if (pHttpInt->pcszCAFile)
- pcszCAFile = pHttpInt->pcszCAFile;
- if (RTFileExists(pcszCAFile))
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- }
-
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
- if (CURL_FAILED(rcCurl))
- return VERR_INTERNAL_ERROR;
-
- /*
- * Open the output file.
- */
- RTFILE hFile;
- int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE);
- if (RT_SUCCESS(rc))
- {
- rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile);
- if (!CURL_FAILED(rcCurl))
- {
- /*
- * Perform the request.
- */
- rcCurl = curl_easy_perform(pHttpInt->pCurl);
- rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
- }
- else
- rc = VERR_INTERNAL_ERROR;
-
- int rc2 = RTFileClose(hFile);
- if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
- rc = rc2;
- }
-
- return rc;
-}
-
diff --git a/src/VBox/Runtime/common/misc/uri.cpp b/src/VBox/Runtime/common/misc/uri.cpp
index f2400dd..99b96cc 100644
--- a/src/VBox/Runtime/common/misc/uri.cpp
+++ b/src/VBox/Runtime/common/misc/uri.cpp
@@ -30,10 +30,18 @@
*******************************************************************************/
#include <iprt/uri.h>
-#include <iprt/string.h>
-#include <iprt/mem.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
#include <iprt/path.h>
-#include <iprt/stream.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** Internal magic value we use to check if a RTURIPARSED structure has made it thru RTUriParse. */
+#define RTURIPARSED_MAGIC UINT32_C(0x439e0745)
+
/* General URI format:
@@ -47,22 +55,19 @@
*/
-/*******************************************************************************
-* Private RTUri helper *
-*******************************************************************************/
-
-/* The following defines characters which have to be % escaped:
- control = 00-1F
- space = ' '
- delims = '<' , '>' , '#' , '%' , '"'
- unwise = '{' , '}' , '|' , '\' , '^' , '[' , ']' , '`'
-*/
+/**
+ * The following defines characters which have to be % escaped:
+ * control = 00-1F
+ * space = ' '
+ * delims = '<' , '>' , '#' , '%' , '"'
+ * unwise = '{' , '}' , '|' , '\' , '^' , '[' , ']' , '`'
+ */
#define URI_EXCLUDED(a) \
- ((a) >= 0x0 && (a) <= 0x20) \
- || ((a) >= 0x5B && (a) <= 0x5E) \
- || ((a) >= 0x7B && (a) <= 0x7D) \
- || (a) == '<' || (a) == '>' || (a) == '#' \
- || (a) == '%' || (a) == '"' || (a) == '`'
+ ( ((a) >= 0x0 && (a) <= 0x20) \
+ || ((a) >= 0x5B && (a) <= 0x5E) \
+ || ((a) >= 0x7B && (a) <= 0x7D) \
+ || (a) == '<' || (a) == '>' || (a) == '#' \
+ || (a) == '%' || (a) == '"' || (a) == '`' )
static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax)
{
@@ -73,13 +78,14 @@ static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax)
size_t cbLen = RT_MIN(strlen(pszString), cchMax);
/* The new string can be max 3 times in size of the original string. */
- char *pszNew = (char*)RTMemAlloc(cbLen * 3 + 1);
+ char *pszNew = RTStrAlloc(cbLen * 3 + 1);
if (!pszNew)
return NULL;
+
char *pszRes = NULL;
size_t iIn = 0;
size_t iOut = 0;
- while(iIn < cbLen)
+ while (iIn < cbLen)
{
if (URI_EXCLUDED(pszString[iIn]))
{
@@ -111,190 +117,473 @@ static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax)
return pszRes;
}
-static char *rtUriPercentDecodeN(const char *pszString, size_t cchMax)
-{
- if (!pszString)
- return NULL;
- int rc = VINF_SUCCESS;
- size_t cbLen = RT_MIN(strlen(pszString), cchMax);
- /* The new string can only get smaller. */
- char *pszNew = (char*)RTMemAlloc(cbLen + 1);
- if (!pszNew)
- return NULL;
- char *pszRes = NULL;
- size_t iIn = 0;
- size_t iOut = 0;
- while(iIn < cbLen)
+static char *rtUriPercentDecodeN(const char *pszString, size_t cchString)
+{
+ AssertPtr(pszString);
+ Assert(strlen(pszString) >= cchString);
+
+ /*
+ * The new string can only get smaller, so use the input length as a
+ * staring buffer size.
+ */
+ char *pszDecoded = RTStrAlloc(cchString + 1);
+ if (pszDecoded)
{
- if (pszString[iIn] == '%')
+ /*
+ * Knowing that the pszString itself is valid UTF-8, we only have to
+ * validate the escape sequences.
+ */
+ size_t cchLeft = cchString;
+ char const *pchSrc = pszString;
+ char *pchDst = pszDecoded;
+ while (cchLeft > 0)
{
- /* % encoding means the percent sign and exactly 2 hexadecimal
- * digits describing the ASCII number of the character. */
- ++iIn;
- char szNum[] = { pszString[iIn++], pszString[iIn++], '\0' };
- uint8_t u8;
- rc = RTStrToUInt8Ex(szNum, NULL, 16, &u8);
- if (RT_FAILURE(rc))
+ const char *pchPct = (const char *)memchr(pchSrc, '%', cchLeft);
+ if (pchPct)
+ {
+ size_t cchBefore = pchPct - pchSrc;
+ if (cchBefore)
+ {
+ memcpy(pchDst, pchSrc, cchBefore);
+ pchDst += cchBefore;
+ pchSrc += cchBefore;
+ cchLeft -= cchBefore;
+ }
+
+ char chHigh, chLow;
+ if ( cchLeft >= 3
+ && RT_C_IS_XDIGIT(chHigh = pchSrc[1])
+ && RT_C_IS_XDIGIT(chLow = pchSrc[2]))
+ {
+ uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
+ b <<= 4;
+ b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
+ *pchDst++ = (char)b;
+ pchSrc += 3;
+ cchLeft -= 3;
+ }
+ else
+ {
+ AssertFailed();
+ *pchDst++ = *pchSrc++;
+ cchLeft--;
+ }
+ }
+ else
+ {
+ memcpy(pchDst, pchSrc, cchLeft);
+ pchDst += cchLeft;
+ pchSrc += cchLeft;
+ cchLeft = 0;
break;
- pszNew[iOut] = u8;
+ }
}
- else
- pszNew[iOut] = pszString[iIn++];
- ++iOut;
+
+ *pchDst = '\0';
+
+ /*
+ * If we've got lof space room in the result string, reallocate it.
+ */
+ size_t cchDecoded = pchDst - pszDecoded;
+ Assert(cchDecoded <= cchString);
+ // if (cchString - cchDecoded > 64) - enable later!
+ RTStrRealloc(&pszDecoded, cchDecoded + 1);
}
- if (RT_SUCCESS(rc))
+ return pszDecoded;
+}
+
+
+static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
+{
+ /*
+ * Validate the input and clear the output.
+ */
+ AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
+ RT_ZERO(*pParsed);
+ pParsed->uAuthorityPort = UINT32_MAX;
+
+ AssertPtrReturn(pszUri, VERR_INVALID_POINTER);
+
+ size_t const cchUri = strlen(pszUri);
+ if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
+ else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;
+
+ /*
+ * Validating escaped text sequences is much simpler if we know that
+ * that the base URI string is valid. Also, we don't necessarily trust
+ * the developer calling us to remember to do this.
+ */
+ int rc = RTStrValidateEncoding(pszUri);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * RFC-3986, section 3.1:
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ *
+ * The scheme ends with a ':', which we also skip here.
+ */
+ size_t off = 0;
+ char ch = pszUri[off++];
+ if (RT_LIKELY(RT_C_IS_ALPHA(ch))) { /* likely */ }
+ else return VERR_URI_INVALID_SCHEME;
+ for (;;)
{
- pszNew[iOut] = '\0';
- if (iOut != iIn)
+ ch = pszUri[off];
+ if (ch == ':')
+ break;
+ if (RT_LIKELY(RT_C_IS_ALNUM(ch) || ch == '.' || ch == '-' || ch == '+')) { /* likely */ }
+ else return VERR_URI_INVALID_SCHEME;
+ off++;
+ }
+ pParsed->cchScheme = off;
+
+ /* Require the scheme length to be at least two chars so we won't confuse
+ it with a path starting with a DOS drive letter specification. */
+ if (RT_LIKELY(off >= 2)) { /* likely */ }
+ else return VERR_URI_INVALID_SCHEME;
+
+ off++; /* (skip colon) */
+
+ /*
+ * Find the end of the path, we'll need this several times.
+ * Also, while we're potentially scanning the whole thing, check for '%'.
+ */
+ size_t const offHash = RTStrOffCharOrTerm(&pszUri[off], '#') + off;
+ size_t const offQuestionMark = RTStrOffCharOrTerm(&pszUri[off], '?') + off;
+
+ if (memchr(pszUri, '%', cchUri) != NULL)
+ pParsed->fFlags |= RTURIPARSED_F_CONTAINS_ESCAPED_CHARS;
+
+ /*
+ * RFC-3986, section 3.2:
+ * The authority component is preceeded by a double slash ("//")...
+ */
+ if ( pszUri[off] == '/'
+ && pszUri[off + 1] == '/')
+ {
+ off += 2;
+ pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
+ pParsed->fFlags |= RTURIPARSED_F_HAVE_AUTHORITY;
+
+ /*
+ * RFC-3986, section 3.2:
+ * ...and is terminated by the next slash ("/"), question mark ("?"),
+ * or number sign ("#") character, or by the end of the URI.
+ */
+ const char *pszAuthority = &pszUri[off];
+ size_t cchAuthority = RTStrOffCharOrTerm(pszAuthority, '/');
+ cchAuthority = RT_MIN(cchAuthority, offHash - off);
+ cchAuthority = RT_MIN(cchAuthority, offQuestionMark - off);
+ pParsed->cchAuthority = cchAuthority;
+
+ /* The Authority can be empty, like for: file:///usr/bin/grep */
+ if (cchAuthority > 0)
{
- /* If the source and target strings have different size, recreate
- * the target string with the correct size. */
- pszRes = RTStrDupN(pszNew, iOut);
- RTStrFree(pszNew);
+ pParsed->cchAuthorityHost = cchAuthority;
+
+ /*
+ * If there is a userinfo part, it is ended by a '@'.
+ */
+ const char *pszAt = (const char *)memchr(pszAuthority, '@', cchAuthority);
+ if (pszAt)
+ {
+ size_t cchTmp = pszAt - pszAuthority;
+ pParsed->offAuthorityHost += cchTmp + 1;
+ pParsed->cchAuthorityHost -= cchTmp + 1;
+
+ /* If there is a password part, it's separated from the username with a colon. */
+ const char *pszColon = (const char *)memchr(pszAuthority, ':', cchTmp);
+ if (pszColon)
+ {
+ pParsed->cchAuthorityUsername = pszColon - pszAuthority;
+ pParsed->offAuthorityPassword = &pszColon[1] - pszUri;
+ pParsed->cchAuthorityPassword = pszAt - &pszColon[1];
+ }
+ else
+ {
+ pParsed->cchAuthorityUsername = cchTmp;
+ pParsed->offAuthorityPassword = off + cchTmp;
+ }
+ }
+
+ /*
+ * If there is a port part, its after the last colon in the host part.
+ */
+ const char *pszColon = (const char *)memrchr(&pszUri[pParsed->offAuthorityHost], ':', pParsed->cchAuthorityHost);
+ if (pszColon)
+ {
+ size_t cchTmp = &pszUri[pParsed->offAuthorityHost + pParsed->cchAuthorityHost] - &pszColon[1];
+ pParsed->cchAuthorityHost -= cchTmp + 1;
+
+ pParsed->uAuthorityPort = 0;
+ while (cchTmp-- > 0)
+ {
+ ch = *++pszColon;
+ if ( RT_C_IS_DIGIT(ch)
+ && pParsed->uAuthorityPort < UINT32_MAX / UINT32_C(10))
+ {
+ pParsed->uAuthorityPort *= 10;
+ pParsed->uAuthorityPort += ch - '0';
+ }
+ else
+ return VERR_URI_INVALID_PORT_NUMBER;
+ }
+ }
}
- else
- pszRes = pszNew;
+
+ /* Skip past the authority. */
+ off += cchAuthority;
}
else
- RTStrFree(pszNew);
+ pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
+
+ /*
+ * RFC-3986, section 3.3: Path
+ * The path is terminated by the first question mark ("?")
+ * or number sign ("#") character, or by the end of the URI.
+ */
+ pParsed->offPath = off;
+ pParsed->cchPath = RT_MIN(offHash, offQuestionMark) - off;
+ off += pParsed->cchPath;
+
+ /*
+ * RFC-3986, section 3.4: Query
+ * The query component is indicated by the first question mark ("?")
+ * character and terminated by a number sign ("#") character or by the
+ * end of the URI.
+ */
+ if ( off == offQuestionMark
+ && off < cchUri)
+ {
+ Assert(pszUri[offQuestionMark] == '?');
+ pParsed->offQuery = ++off;
+ pParsed->cchQuery = offHash - off;
+ off = offHash;
+ }
+ else
+ {
+ Assert(!pszUri[offQuestionMark]);
+ pParsed->offQuery = off;
+ }
- return pszRes;
-}
+ /*
+ * RFC-3986, section 3.5: Fragment
+ * A fragment identifier component is indicated by the presence of a
+ * number sign ("#") character and terminated by the end of the URI.
+ */
+ if ( off == offHash
+ && off < cchUri)
+ {
+ pParsed->offFragment = ++off;
+ pParsed->cchFragment = cchUri - off;
+ }
+ else
+ {
+ Assert(!pszUri[offHash]);
+ pParsed->offFragment = off;
+ }
-static bool rtUriFindSchemeEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
-{
- size_t i = iStart;
- /* The scheme has to end with ':'. */
- while(i < iStart + cbLen)
+ /*
+ * If there are any escape sequences, validate them.
+ *
+ * This is reasonably simple as we already know that the string is valid UTF-8
+ * before they get decoded. Thus we only have to validate the escaped sequences.
+ */
+ if (pParsed->fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS)
{
- if (pszUri[i] == ':')
+ const char *pchSrc = (const char *)memchr(pszUri, '%', cchUri);
+ AssertReturn(pchSrc, VERR_INTERNAL_ERROR);
+ do
{
- *piEnd = i;
- return true;
- }
- ++i;
+ char szUtf8Seq[8];
+ unsigned cchUtf8Seq = 0;
+ unsigned cchNeeded = 0;
+ size_t cchLeft = &pszUri[cchUri] - pchSrc;
+ do
+ {
+ if (cchLeft >= 3)
+ {
+ char chHigh = pchSrc[1];
+ char chLow = pchSrc[2];
+ if ( RT_C_IS_XDIGIT(chHigh)
+ && RT_C_IS_XDIGIT(chLow))
+ {
+ uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10;
+ b <<= 4;
+ b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10;
+
+ if (!(b & 0x80))
+ {
+ /* We don't want the string to be terminated prematurely. */
+ if (RT_LIKELY(b != 0)) { /* likely */ }
+ else return VERR_URI_ESCAPED_ZERO;
+
+ /* Check that we're not expecting more UTF-8 bytes. */
+ if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
+ else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
+ }
+ /* Are we waiting UTF-8 bytes? */
+ else if (cchNeeded > 0)
+ {
+ if (RT_LIKELY(!(b & 0x40))) { /* likely */ }
+ else return VERR_URI_INVALID_ESCAPED_UTF8_CONTINUATION_BYTE;
+
+ szUtf8Seq[cchUtf8Seq++] = (char)b;
+ if (--cchNeeded == 0)
+ {
+ szUtf8Seq[cchUtf8Seq] = '\0';
+ rc = RTStrValidateEncoding(szUtf8Seq);
+ if (RT_FAILURE(rc))
+ return VERR_URI_ESCAPED_CHARS_NOT_VALID_UTF8;
+ cchUtf8Seq = 0;
+ }
+ }
+ /* Start a new UTF-8 sequence. */
+ else
+ {
+ if ((b & 0xf8) == 0xf0)
+ cchNeeded = 3;
+ else if ((b & 0xf0) == 0xe0)
+ cchNeeded = 2;
+ else if ((b & 0xe0) == 0xc0)
+ cchNeeded = 1;
+ else
+ return VERR_URI_INVALID_ESCAPED_UTF8_LEAD_BYTE;
+ szUtf8Seq[0] = (char)b;
+ cchUtf8Seq = 1;
+ }
+ pchSrc += 3;
+ cchLeft -= 3;
+ }
+ else
+ return VERR_URI_INVALID_ESCAPE_SEQ;
+ }
+ else
+ return VERR_URI_INVALID_ESCAPE_SEQ;
+ } while (cchLeft > 0 && pchSrc[0] == '%');
+
+ /* Check that we're not expecting more UTF-8 bytes. */
+ if (RT_LIKELY(cchNeeded == 0)) { /* likely */ }
+ else return VERR_URI_MISSING_UTF8_CONTINUATION_BYTE;
+
+ /* next */
+ pchSrc = (const char *)memchr(pchSrc, '%', cchLeft);
+ } while (pchSrc);
}
- return false;
+
+ pParsed->u32Magic = RTURIPARSED_MAGIC;
+ return VINF_SUCCESS;
}
-static bool rtUriCheckAuthorityStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
+
+
+RTDECL(int) RTUriParse(const char *pszUri, PRTURIPARSED pParsed)
{
- /* The authority have to start with '//' */
- if ( cbLen >= 2
- && pszUri[iStart ] == '/'
- && pszUri[iStart + 1] == '/')
- {
- *piStart = iStart + 2;
- return true;
- }
+ return rtUriParse(pszUri, pParsed);
+}
+
- return false;
+RTDECL(char *) RTUriParsedScheme(const char *pszUri, PCRTURIPARSED pParsed)
+{
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ return RTStrDupN(pszUri, pParsed->cchScheme);
}
-static bool rtUriFindAuthorityEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
+
+RTDECL(char *) RTUriParsedAuthority(const char *pszUri, PCRTURIPARSED pParsed)
{
- size_t i = iStart;
- /* The authority can end with '/' || '?' || '#'. */
- while(i < iStart + cbLen)
- {
- if ( pszUri[i] == '/'
- || pszUri[i] == '?'
- || pszUri[i] == '#')
- {
- *piEnd = i;
- return true;
- }
- ++i;
- }
- return false;
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchAuthority || (pParsed->fFlags & RTURIPARSED_F_HAVE_AUTHORITY))
+ return rtUriPercentDecodeN(&pszUri[pParsed->offAuthority], pParsed->cchAuthority);
+ return NULL;
}
-static bool rtUriCheckPathStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
+
+RTDECL(char *) RTUriParsedAuthorityUsername(const char *pszUri, PCRTURIPARSED pParsed)
{
- /* The path could start with a '/'. */
- if ( cbLen >= 1
- && pszUri[iStart] == '/')
- {
- *piStart = iStart; /* Including '/' */
- return true;
- }
- /* '?' || '#' means there is no path. */
- if ( cbLen >= 1
- && ( pszUri[iStart] == '?'
- || pszUri[iStart] == '#'))
- return false;
- /* All other values are allowed. */
- *piStart = iStart;
- return true;
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchAuthorityUsername)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityUsername], pParsed->cchAuthorityUsername);
+ return NULL;
}
-static bool rtUriFindPathEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
+
+RTDECL(char *) RTUriParsedAuthorityPassword(const char *pszUri, PCRTURIPARSED pParsed)
{
- size_t i = iStart;
- /* The path can end with '?' || '#'. */
- while(i < iStart + cbLen)
- {
- if ( pszUri[i] == '?'
- || pszUri[i] == '#')
- {
- *piEnd = i;
- return true;
- }
- ++i;
- }
- return false;
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchAuthorityPassword)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityPassword], pParsed->cchAuthorityPassword);
+ return NULL;
}
-static bool rtUriCheckQueryStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
+
+RTDECL(char *) RTUriParsedAuthorityHost(const char *pszUri, PCRTURIPARSED pParsed)
{
- /* The query start with a '?'. */
- if ( cbLen >= 1
- && pszUri[iStart] == '?')
- {
- *piStart = iStart + 1; /* Excluding '?' */
- return true;
- }
- return false;
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchAuthorityHost)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offAuthorityHost], pParsed->cchAuthorityHost);
+ return NULL;
}
-static bool rtUriFindQueryEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
+
+RTDECL(uint32_t) RTUriParsedAuthorityPort(const char *pszUri, PCRTURIPARSED pParsed)
{
- size_t i = iStart;
- /* The query can end with '?' || '#'. */
- while(i < iStart + cbLen)
- {
- if (pszUri[i] == '#')
- {
- *piEnd = i;
- return true;
- }
- ++i;
- }
- return false;
+ AssertPtrReturn(pszUri, UINT32_MAX);
+ AssertPtrReturn(pParsed, UINT32_MAX);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, UINT32_MAX);
+ return pParsed->uAuthorityPort;
}
-static bool rtUriCheckFragmentStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
+
+RTDECL(char *) RTUriParsedPath(const char *pszUri, PCRTURIPARSED pParsed)
{
- /* The fragment start with a '#'. */
- if ( cbLen >= 1
- && pszUri[iStart] == '#')
- {
- *piStart = iStart + 1; /* Excluding '#' */
- return true;
- }
- return false;
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchPath)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offPath], pParsed->cchPath);
+ return NULL;
}
/*******************************************************************************
* Public RTUri interface *
*******************************************************************************/
-/*******************************************************************************
-* Generic Uri methods *
-*******************************************************************************/
+RTDECL(char *) RTUriParsedQuery(const char *pszUri, PCRTURIPARSED pParsed)
+{
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchQuery)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offQuery], pParsed->cchQuery);
+ return NULL;
+}
+
-RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment)
+RTDECL(char *) RTUriParsedFragment(const char *pszUri, PCRTURIPARSED pParsed)
+{
+ AssertPtrReturn(pszUri, NULL);
+ AssertPtrReturn(pParsed, NULL);
+ AssertReturn(pParsed->u32Magic == RTURIPARSED_MAGIC, NULL);
+ if (pParsed->cchFragment)
+ return rtUriPercentDecodeN(&pszUri[pParsed->offFragment], pParsed->cchFragment);
+ return NULL;
+}
+
+
+RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
+ const char *pszFragment)
{
if (!pszScheme) /* Scheme is minimum requirement */
return NULL;
@@ -339,9 +628,11 @@ RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, co
cbSize += strlen(pszFragment1) + 1;
}
- char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize);
+ char *pszTmp = pszResult = (char *)RTStrAlloc(cbSize);
if (!pszResult)
break;
+ RT_BZERO(pszTmp, cbSize);
+
/* Compose the target uri string. */
RTStrCatP(&pszTmp, &cbSize, pszScheme);
RTStrCatP(&pszTmp, &cbSize, ":");
@@ -364,7 +655,7 @@ RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, co
RTStrCatP(&pszTmp, &cbSize, "#");
RTStrCatP(&pszTmp, &cbSize, pszFragment1);
}
- }while (0);
+ } while (0);
/* Cleanup */
if (pszAuthority1)
@@ -379,306 +670,106 @@ RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, co
return pszResult;
}
-RTR3DECL(bool) RTUriHasScheme(const char *pszUri, const char *pszScheme)
-{
- bool fRes = false;
- char *pszTmp = RTUriScheme(pszUri);
- if (pszTmp)
- {
- fRes = RTStrNICmp(pszScheme, pszTmp, strlen(pszTmp)) == 0;
- RTStrFree(pszTmp);
- }
- return fRes;
-}
-RTR3DECL(char *) RTUriScheme(const char *pszUri)
+RTDECL(bool) RTUriIsSchemeMatch(const char *pszUri, const char *pszScheme)
{
- AssertPtrReturn(pszUri, NULL);
-
- size_t iPos1;
- size_t cbLen = strlen(pszUri);
- if (rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return rtUriPercentDecodeN(pszUri, iPos1);
- return NULL;
+ AssertPtrReturn(pszUri, false);
+ size_t const cchScheme = strlen(pszScheme);
+ return RTStrNICmp(pszUri, pszScheme, cchScheme) == 0
+ && pszUri[cchScheme] == ':';
}
-RTR3DECL(char *) RTUriAuthority(const char *pszUri)
-{
- AssertPtrReturn(pszUri, NULL);
-
- size_t iPos1;
- size_t cbLen = strlen(pszUri);
- /* Find the end of the scheme. */
- if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return NULL; /* no URI */
- else
- ++iPos1; /* Skip ':' */
-
- size_t iPos2;
- /* Find the start of the authority. */
- if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
- {
- size_t iPos3 = cbLen;
- /* Find the end of the authority. If not found, the rest of the string
- * is used. */
- rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3);
- if (iPos3 > iPos2) /* Length check */
- return rtUriPercentDecodeN(&pszUri[iPos2], iPos3 - iPos2);
- else
- return NULL;
- }
- return NULL;
-}
-RTR3DECL(char *) RTUriPath(const char *pszUri)
+/* temporarily kept around till Andy stops using it. */
+RTDECL(char *) RTUriPath(const char *pszUri)
{
- AssertPtrReturn(pszUri, NULL);
-
- size_t iPos1;
- size_t cbLen = strlen(pszUri);
- /* Find the end of the scheme. */
- if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return NULL; /* no URI */
- else
- ++iPos1; /* Skip ':' */
-
- size_t iPos2;
- size_t iPos3 = iPos1; /* Skip if no authority is found */
- /* Find the start of the authority. */
- if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
- {
- /* Find the end of the authority. If not found, then there is no path
- * component, cause the authority is the rest of the string. */
- if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
- return NULL; /* no path! */
- }
-
- size_t iPos4;
- /* Find the start of the path */
- if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
- {
- /* Search for the end of the scheme. */
- size_t iPos5 = cbLen;
- rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5);
- if (iPos5 > iPos4) /* Length check */
- return rtUriPercentDecodeN(&pszUri[iPos4], iPos5 - iPos4);
- }
-
+ RTURIPARSED Parsed;
+ int rc = rtUriParse(pszUri, &Parsed);
+ if (RT_SUCCESS(rc))
+ if (Parsed.cchPath)
+ return rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
return NULL;
}
-RTR3DECL(char *) RTUriQuery(const char *pszUri)
-{
- AssertPtrReturn(pszUri, NULL);
-
- size_t iPos1;
- size_t cbLen = strlen(pszUri);
- /* Find the end of the scheme. */
- if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return NULL; /* no URI */
- else
- ++iPos1; /* Skip ':' */
-
- size_t iPos2;
- size_t iPos3 = iPos1; /* Skip if no authority is found */
- /* Find the start of the authority. */
- if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
- {
- /* Find the end of the authority. If not found, then there is no path
- * component, cause the authority is the rest of the string. */
- if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
- return NULL; /* no path! */
- }
- size_t iPos4;
- size_t iPos5 = iPos3; /* Skip if no path is found */
- /* Find the start of the path */
- if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
- {
- /* Find the end of the path. If not found, then there is no query
- * component, cause the path is the rest of the string. */
- if (!rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5))
- return NULL; /* no query! */
- }
-
- size_t iPos6;
- /* Find the start of the query */
- if (rtUriCheckQueryStart(pszUri, iPos5, cbLen - iPos5, &iPos6))
- {
- /* Search for the end of the query. */
- size_t iPos7 = cbLen;
- rtUriFindQueryEnd(pszUri, iPos6, cbLen - iPos6, &iPos7);
- if (iPos7 > iPos6) /* Length check */
- return rtUriPercentDecodeN(&pszUri[iPos6], iPos7 - iPos6);
- }
-
- return NULL;
-}
-
-RTR3DECL(char *) RTUriFragment(const char *pszUri)
+RTDECL(char *) RTUriFileCreate(const char *pszPath)
{
- AssertPtrReturn(pszUri, NULL);
-
- size_t iPos1;
- size_t cbLen = strlen(pszUri);
- /* Find the end of the scheme. */
- if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return NULL; /* no URI */
- else
- ++iPos1; /* Skip ':' */
-
- size_t iPos2;
- size_t iPos3 = iPos1; /* Skip if no authority is found */
- /* Find the start of the authority. */
- if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
- {
- /* Find the end of the authority. If not found, then there is no path
- * component, cause the authority is the rest of the string. */
- if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
- return NULL; /* no path! */
- }
-
- size_t iPos4;
- size_t iPos5 = iPos3; /* Skip if no path is found */
- /* Find the start of the path */
- if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
- {
- /* Find the end of the path. If not found, then there is no query
- * component, cause the path is the rest of the string. */
- if (!rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5))
- return NULL; /* no query! */
- }
-
- size_t iPos6;
- size_t iPos7 = iPos5; /* Skip if no query is found */
- /* Find the start of the query */
- if (rtUriCheckQueryStart(pszUri, iPos5, cbLen - iPos5, &iPos6))
- {
- /* Find the end of the query If not found, then there is no fragment
- * component, cause the query is the rest of the string. */
- if (!rtUriFindQueryEnd(pszUri, iPos6, cbLen - iPos6, &iPos7))
- return NULL; /* no query! */
- }
-
-
- size_t iPos8;
- /* Find the start of the fragment */
- if (rtUriCheckFragmentStart(pszUri, iPos7, cbLen - iPos7, &iPos8))
+ char *pszResult = NULL;
+ if (pszPath)
{
- /* There could be nothing behind a fragment. So use the rest of the
- * string. */
- if (cbLen > iPos8) /* Length check */
- return rtUriPercentDecodeN(&pszUri[iPos8], cbLen - iPos8);
+ /* Create the percent encoded strings and calculate the necessary uri length. */
+ char *pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
+ if (pszPath1)
+ {
+ size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */
+ if (pszPath1[0] != '/')
+ ++cbSize;
+ char *pszTmp = pszResult = RTStrAlloc(cbSize);
+ if (pszResult)
+ {
+ /* Compose the target uri string. */
+ *pszTmp = '\0';
+ RTStrCatP(&pszTmp, &cbSize, "file://");
+ if (pszPath1[0] != '/')
+ RTStrCatP(&pszTmp, &cbSize, "/");
+ RTStrCatP(&pszTmp, &cbSize, pszPath1);
+ }
+ RTStrFree(pszPath1);
+ }
}
- return NULL;
+ return pszResult;
}
/*******************************************************************************
* File Uri methods *
*******************************************************************************/
-RTR3DECL(char *) RTUriFileCreate(const char *pszPath)
-{
- if (!pszPath)
- return NULL;
-
- char *pszResult = 0;
- char *pszPath1 = 0;
-
- do
- {
- /* Create the percent encoded strings and calculate the necessary uri
- * length. */
- pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
- if (!pszPath1)
- break;
- size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */
- if (pszPath1[0] != '/')
- ++cbSize;
- char *pszTmp = pszResult = (char*)RTMemAllocZ(cbSize);
- if (!pszResult)
- break;
- /* Compose the target uri string. */
- RTStrCatP(&pszTmp, &cbSize, "file://");
- if (pszPath1[0] != '/')
- RTStrCatP(&pszTmp, &cbSize, "/");
- RTStrCatP(&pszTmp, &cbSize, pszPath1);
- }while (0);
-
- /* Cleanup */
- if (pszPath1)
- RTStrFree(pszPath1);
-
- return pszResult;
-}
-
-RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
+RTDECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
{
return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX);
}
-RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
+
+RTDECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
{
AssertPtrReturn(pszUri, NULL);
+ AssertReturn(uFormat == URI_FILE_FORMAT_AUTO || uFormat == URI_FILE_FORMAT_UNIX || uFormat == URI_FILE_FORMAT_WIN, NULL);
- size_t iPos1;
- size_t cbLen = RT_MIN(strlen(pszUri), cchMax);
- /* Find the end of the scheme. */
- if (!rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
- return NULL; /* no URI */
- else
- ++iPos1; /* Skip ':' */
+ /* Auto is based on the current OS. */
+ if (uFormat == URI_FILE_FORMAT_AUTO)
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ uFormat = URI_FILE_FORMAT_WIN;
+#else
+ uFormat = URI_FILE_FORMAT_UNIX;
+#endif
/* Check that this is a file Uri */
- if (RTStrNICmp(pszUri, "file:", iPos1) != 0)
+ if (RTStrNICmp(pszUri, RT_STR_TUPLE("file:")) != 0)
return NULL;
- size_t iPos2;
- size_t iPos3 = iPos1; /* Skip if no authority is found */
- /* Find the start of the authority. */
- if (rtUriCheckAuthorityStart(pszUri, iPos1, cbLen - iPos1, &iPos2))
+ RTURIPARSED Parsed;
+ int rc = rtUriParse(pszUri, &Parsed);
+ if (RT_SUCCESS(rc) && Parsed.cchPath)
{
- /* Find the end of the authority. If not found, then there is no path
- * component, cause the authority is the rest of the string. */
- if (!rtUriFindAuthorityEnd(pszUri, iPos2, cbLen - iPos2, &iPos3))
- return NULL; /* no path! */
- }
-
- size_t iPos4;
- /* Find the start of the path */
- if (rtUriCheckPathStart(pszUri, iPos3, cbLen - iPos3, &iPos4))
- {
- uint32_t uFIntern = uFormat;
- /* Auto is based on the current host OS. */
- if (uFormat == URI_FILE_FORMAT_AUTO)
-#ifdef RT_OS_WINDOWS
- uFIntern = URI_FILE_FORMAT_WIN;
-#else /* RT_OS_WINDOWS */
- uFIntern = URI_FILE_FORMAT_UNIX;
-#endif /* !RT_OS_WINDOWS */
-
- if ( uFIntern != URI_FILE_FORMAT_UNIX
- && pszUri[iPos4] == '/')
- ++iPos4;
- /* Search for the end of the scheme. */
- size_t iPos5 = cbLen;
- rtUriFindPathEnd(pszUri, iPos4, cbLen - iPos4, &iPos5);
- if (iPos5 > iPos4) /* Length check */
+ /* Special hack for DOS path like file:///c:/WINDOWS/clock.avi where we
+ have to drop the leading slash that was used to separate the authority
+ from the path. */
+ if ( uFormat == URI_FILE_FORMAT_WIN
+ && Parsed.cchPath >= 3
+ && pszUri[Parsed.offPath] == '/'
+ && pszUri[Parsed.offPath + 2] == ':'
+ && RT_C_IS_ALPHA(pszUri[Parsed.offPath + 1]) )
{
- char *pszPath = rtUriPercentDecodeN(&pszUri[iPos4], iPos5 - iPos4);
- if (uFIntern == URI_FILE_FORMAT_UNIX)
- return RTPathChangeToUnixSlashes(pszPath, true);
- else if (uFIntern == URI_FILE_FORMAT_WIN)
- return RTPathChangeToDosSlashes(pszPath, true);
- else
- {
- RTStrFree(pszPath);
- AssertMsgFailed(("Unknown uri file format %u", uFIntern));
- return NULL;
- }
+ Parsed.offPath++;
+ Parsed.cchPath--;
}
- }
+ char *pszPath = rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
+ if (uFormat == URI_FILE_FORMAT_UNIX)
+ return RTPathChangeToUnixSlashes(pszPath, true);
+ Assert(uFormat == URI_FILE_FORMAT_WIN);
+ return RTPathChangeToDosSlashes(pszPath, true);
+ }
return NULL;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp b/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp
similarity index 54%
copy from src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
copy to src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp
index c221df4..901afb4 100644
--- a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp
@@ -1,10 +1,10 @@
-/* $Id: assert-r0drv-darwin.cpp $ */
+/* $Id: RTPathEnsureTrailingSeparator.cpp $ */
/** @file
- * IPRT - Assertion Workers, Ring-0 Drivers, Darwin.
+ * IPRT - RTPathEnsureTrailingSeparator
*/
/*
- * Copyright (C) 2007-2011 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -25,44 +25,40 @@
*/
-/*******************************************************************************
-* Header Files *
-*******************************************************************************/
-#include "the-darwin-kernel.h"
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
#include "internal/iprt.h"
-#include <iprt/assert.h>
-
-#include <iprt/asm.h>
-#include <iprt/log.h>
-#include <iprt/stdarg.h>
+#include <iprt/path.h>
#include <iprt/string.h>
+#include <iprt/ctype.h>
-#include "internal/assert.h"
-
-
-DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
-{
- printf("\r\n!!Assertion Failed!!\r\n"
- "Expression: %s\r\n"
- "Location : %s(%d) %s\r\n",
- pszExpr, pszFile, uLine, pszFunction);
-}
-DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
+RTDECL(size_t) RTPathEnsureTrailingSeparator(char *pszPath, size_t cbPath)
{
- char szMsg[256];
+ size_t off = strlen(pszPath);
+ if (off > 0)
+ {
+ char ch = pszPath[off - 1];
+ if (RTPATH_IS_SLASH(ch) || RTPATH_IS_VOLSEP(ch))
+ return off;
+ if (off + 2 <= cbPath)
+ {
+ pszPath[off++] = RTPATH_SLASH;
+ pszPath[off] = '\0';
+ return off;
+ }
+ }
+ else if (off + 3 <= cbPath)
+ {
+ pszPath[off++] = '.';
+ pszPath[off++] = RTPATH_SLASH;
+ pszPath[off] = '\0';
+ return off;
+ }
- RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
- szMsg[sizeof(szMsg) - 1] = '\0';
- printf("%s", szMsg);
-
- NOREF(fInitial);
-}
-
-
-RTR0DECL(void) RTR0AssertPanicSystem(void)
-{
- panic("%s%s", g_szRTAssertMsg1, g_szRTAssertMsg2);
+ return 0;
}
+RT_EXPORT_SYMBOL(RTPathEnsureTrailingSeparator);
diff --git a/src/VBox/Runtime/common/path/RTPathGlob.cpp b/src/VBox/Runtime/common/path/RTPathGlob.cpp
new file mode 100644
index 0000000..16b4842
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathGlob.cpp
@@ -0,0 +1,2140 @@
+/* $Id: RTPathGlob.cpp $ */
+/** @file
+ * IPRT - RTPathGlob
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
+#include <iprt/dir.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+
+#if defined(RT_OS_WINDOWS)
+# include <Windows.h>
+
+#elif defined(RT_OS_OS2)
+# define INCL_BASE
+# include <os2.h>
+# undef RT_MAX /* collision */
+
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** Maximum number of results. */
+#define RTPATHGLOB_MAX_RESULTS _32K
+/** Maximum number of zero-or-more wildcards in a pattern.
+ * This limits stack usage and recursion depth, as well as execution time. */
+#define RTPATHMATCH_MAX_ZERO_OR_MORE 24
+/** Maximum number of variable items. */
+#define RTPATHMATCH_MAX_VAR_ITEMS _4K
+
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Matching operation.
+ */
+typedef enum RTPATHMATCHOP
+{
+ RTPATHMATCHOP_INVALID = 0,
+ /** EOS: Returns a match if at end of string. */
+ RTPATHMATCHOP_RETURN_MATCH_IF_AT_END,
+ /** Asterisk: Returns a match (trailing asterisk). */
+ RTPATHMATCHOP_RETURN_MATCH,
+ /** Asterisk: Returns a match (just asterisk), unless it's '.' or '..'. */
+ RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT,
+ /** Plain text: Case sensitive string compare. */
+ RTPATHMATCHOP_STRCMP,
+ /** Plain text: Case insensitive string compare. */
+ RTPATHMATCHOP_STRICMP,
+ /** Question marks: Skips exactly one code point. */
+ RTPATHMATCHOP_SKIP_ONE_CODEPOINT,
+ /** Question marks: Skips exactly RTPATHMATCHCORE::cch code points. */
+ RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS,
+ /** Char set: Requires the next codepoint to be in the ASCII-7 set defined by
+ * RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch. No ranges. */
+ RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7,
+ /** Char set: Requires the next codepoint to not be in the ASCII-7 set defined
+ * by RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch. No ranges. */
+ RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7,
+ /** Char set: Requires the next codepoint to be in the extended set defined by
+ * RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch. Ranges, UTF-8. */
+ RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED,
+ /** Char set: Requires the next codepoint to not be in the extended set defined
+ * by RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch. Ranges, UTF-8. */
+ RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED,
+ /** Variable: Case sensitive variable value compare, RTPATHMATCHCORE::uOp2 is
+ * the variable table index. */
+ RTPATHMATCHOP_VARIABLE_VALUE_CMP,
+ /** Variable: Case insensitive variable value compare, RTPATHMATCHCORE::uOp2 is
+ * the variable table index. */
+ RTPATHMATCHOP_VARIABLE_VALUE_ICMP,
+ /** Asterisk: Match zero or more code points, there must be at least
+ * RTPATHMATCHCORE::cch code points after it. */
+ RTPATHMATCHOP_ZERO_OR_MORE,
+ /** Asterisk: Match zero or more code points, there must be at least
+ * RTPATHMATCHCORE::cch code points after it, unless it's '.' or '..'. */
+ RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT,
+ /** End of valid operations. */
+ RTPATHMATCHOP_END
+} RTPATHMATCHOP;
+
+/**
+ * Matching instruction.
+ */
+typedef struct RTPATHMATCHCORE
+{
+ /** The action to take. */
+ RTPATHMATCHOP enmOpCode;
+ /** Generic value operand. */
+ uint16_t uOp2;
+ /** Generic length operand. */
+ uint16_t cch;
+ /** Generic string pointer operand. */
+ const char *pch;
+} RTPATHMATCHCORE;
+/** Pointer to a matching instruction. */
+typedef RTPATHMATCHCORE *PRTPATHMATCHCORE;
+/** Pointer to a const matching instruction. */
+typedef RTPATHMATCHCORE const *PCRTPATHMATCHCORE;
+
+/**
+ * Path matching instruction allocator.
+ */
+typedef struct RTPATHMATCHALLOC
+{
+ /** Allocated array of instructions. */
+ PRTPATHMATCHCORE paInstructions;
+ /** Index of the next free entry in paScratch. */
+ uint32_t iNext;
+ /** Number of instructions allocated. */
+ uint32_t cAllocated;
+} RTPATHMATCHALLOC;
+/** Pointer to a matching instruction allocator. */
+typedef RTPATHMATCHALLOC *PRTPATHMATCHALLOC;
+
+/**
+ * Path matching cache, mainly intended for variables like the PATH.
+ */
+typedef struct RTPATHMATCHCACHE
+{
+ /** @todo optimize later. */
+ uint32_t iNothingYet;
+} RTPATHMATCHCACHE;
+/** Pointer to a path matching cache. */
+typedef RTPATHMATCHCACHE *PRTPATHMATCHCACHE;
+
+
+
+/** Parsed path entry.*/
+typedef struct RTPATHGLOBPPE
+{
+ /** Normal: Index into RTPATHGLOB::MatchInstrAlloc.paInstructions. */
+ uint32_t iMatchProg : 16;
+ /** Set if this is a normal entry which is matched using iMatchProg. */
+ uint32_t fNormal : 1;
+ /** !fNormal: Plain name that can be dealt with using without
+ * enumerating the whole directory, unless of course the file system is case
+ * sensitive and the globbing isn't (that needs figuring out on a per
+ * directory basis). */
+ uint32_t fPlain : 1;
+ /** !fNormal: Match zero or more subdirectories. */
+ uint32_t fStarStar : 1;
+ /** !fNormal: The whole component is a variable expansion. */
+ uint32_t fExpVariable : 1;
+
+ /** Filter: Set if it only matches directories. */
+ uint32_t fDir : 1;
+ /** Set if it's the final component. */
+ uint32_t fFinal : 1;
+
+ /** Unused bits. */
+ uint32_t fReserved : 2+8;
+} RTPATHGLOBPPE;
+
+
+typedef struct RTPATHGLOB
+{
+ /** Path buffer. */
+ char szPath[RTPATH_MAX];
+ /** Temporary buffers. */
+ union
+ {
+ /** File system object info structure. */
+ RTFSOBJINFO ObjInfo;
+ /** Directory entry buffer. */
+ RTDIRENTRY DirEntry;
+ /** Padding the buffer to an unreasonably large size. */
+ uint8_t abPadding[RTPATH_MAX + sizeof(RTDIRENTRY)];
+ } u;
+
+
+ /** Where to insert the next one.*/
+ PRTPATHGLOBENTRY *ppNext;
+ /** The head pointer. */
+ PRTPATHGLOBENTRY pHead;
+ /** Result count. */
+ uint32_t cResults;
+ /** Counts path overflows. */
+ uint32_t cPathOverflows;
+ /** The input flags. */
+ uint32_t fFlags;
+ /** Matching instruction allocator. */
+ RTPATHMATCHALLOC MatchInstrAlloc;
+ /** Matching state. */
+ RTPATHMATCHCACHE MatchCache;
+
+ /** The pattern string. */
+ const char *pszPattern;
+ /** The parsed path. */
+ PRTPATHPARSED pParsed;
+ /** The component to start with. */
+ uint16_t iFirstComp;
+ /** The corresponding path offset (previous components already present). */
+ uint16_t offFirstPath;
+ /** Path component information we need. */
+ RTPATHGLOBPPE aComps[1];
+} RTPATHGLOB;
+typedef RTPATHGLOB *PRTPATHGLOB;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int rtPathGlobExecRecursiveStarStar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iStarStarComp, size_t offStarStarPath);
+static int rtPathGlobExecRecursiveVarExp(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+static int rtPathGlobExecRecursivePlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+static int rtPathGlobExecRecursiveGeneric(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+
+
+/**
+ * Implements the two variable access functions for a simple one value variable.
+ */
+#define RTPATHMATCHVAR_SIMPLE(a_Name, a_GetStrExpr) \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+ PRTPATHMATCHCACHE pCache) \
+ { \
+ if (iItem == 0) \
+ { \
+ const char *pszValue = a_GetStrExpr; \
+ size_t cchValue = strlen(pszValue); \
+ if (cchValue + 1 <= cbBuf) \
+ { \
+ memcpy(pszBuf, pszValue, cchValue + 1); \
+ *pcchValue = cchValue; \
+ return VINF_EOF; \
+ } \
+ return VERR_BUFFER_OVERFLOW; \
+ } \
+ NOREF(pCache);\
+ return VERR_EOF; \
+ } \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+ size_t *pcchMatched) \
+ { \
+ const char *pszValue = a_GetStrExpr; \
+ size_t cchValue = strlen(pszValue); \
+ if ( cchValue >= cchMatch \
+ && ( !fIgnoreCase \
+ ? memcmp(pszValue, pchMatch, cchValue) == 0 \
+ : RTStrNICmp(pszValue, pchMatch, cchValue) == 0) ) \
+ { \
+ *pcchMatched = cchValue; \
+ return VINF_SUCCESS; \
+ } \
+ return VERR_MISMATCH; \
+ } \
+ typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+/**
+ * Implements mapping a glob variable to an environment variable.
+ */
+#define RTPATHMATCHVAR_SIMPLE_ENVVAR(a_Name, a_pszEnvVar, a_cbMaxValue) \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+ PRTPATHMATCHCACHE pCache) \
+ { \
+ if (iItem == 0) \
+ { \
+ int rc = RTEnvGetEx(RTENV_DEFAULT, a_pszEnvVar, pszBuf, cbBuf, pcchValue); \
+ if (RT_SUCCESS(rc)) \
+ return VINF_EOF; \
+ if (rc != VERR_ENV_VAR_NOT_FOUND) \
+ return rc; \
+ } \
+ NOREF(pCache);\
+ return VERR_EOF; \
+ } \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+ size_t *pcchMatched) \
+ { \
+ char szValue[a_cbMaxValue]; \
+ size_t cchValue; \
+ int rc = RTEnvGetEx(RTENV_DEFAULT, a_pszEnvVar, szValue, sizeof(szValue), &cchValue); \
+ if ( RT_SUCCESS(rc) \
+ && cchValue >= cchMatch \
+ && ( !fIgnoreCase \
+ ? memcmp(szValue, pchMatch, cchValue) == 0 \
+ : RTStrNICmp(szValue, pchMatch, cchValue) == 0) ) \
+ { \
+ *pcchMatched = cchValue; \
+ return VINF_SUCCESS; \
+ } \
+ return VERR_MISMATCH; \
+ } \
+ typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+/**
+ * Implements mapping a glob variable to multiple environment variable values.
+ * @param a_apszVarNames Assumes to be a global variable that RT_ELEMENTS
+ * works correctly on.
+ */
+#define RTPATHMATCHVAR_MULTIPLE_ENVVARS(a_Name, a_apszVarNames, a_cbMaxValue) \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+ PRTPATHMATCHCACHE pCache) \
+ { \
+ if (iItem < RT_ELEMENTS(a_apszVarNames)) \
+ { \
+ int rc = RTEnvGetEx(RTENV_DEFAULT, a_apszVarNames[iItem], pszBuf, cbBuf, pcchValue); \
+ if (RT_SUCCESS(rc)) \
+ return iItem + 1 == RT_ELEMENTS(a_apszVarNames) ? VINF_EOF : VINF_SUCCESS; \
+ if (rc == VERR_ENV_VAR_NOT_FOUND) \
+ rc = VERR_TRY_AGAIN; \
+ return rc; \
+ } \
+ NOREF(pCache);\
+ return VERR_EOF; \
+ } \
+ static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+ size_t *pcchMatched) \
+ { \
+ for (uint32_t iItem = 0; iItem < RT_ELEMENTS(a_apszVarNames); iItem++) \
+ { \
+ char szValue[a_cbMaxValue]; \
+ size_t cchValue; \
+ int rc = RTEnvGetEx(RTENV_DEFAULT, a_apszVarNames[iItem], szValue, sizeof(szValue), &cchValue);\
+ if ( RT_SUCCESS(rc) \
+ && cchValue >= cchMatch \
+ && ( !fIgnoreCase \
+ ? memcmp(szValue, pchMatch, cchValue) == 0 \
+ : RTStrNICmp(szValue, pchMatch, cchValue) == 0) ) \
+ { \
+ *pcchMatched = cchValue; \
+ return VINF_SUCCESS; \
+ } \
+ } \
+ return VERR_MISMATCH; \
+ } \
+ typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+
+RTPATHMATCHVAR_SIMPLE(Arch, RTBldCfgTargetArch());
+RTPATHMATCHVAR_SIMPLE(Bits, RT_XSTR(ARCH_BITS));
+#ifdef RT_OS_WINDOWS
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinAppData, "AppData", RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinProgramData, "ProgramData", RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinProgramFiles, "ProgramFiles", RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinCommonProgramFiles, "CommonProgramFiles", RTPATH_MAX);
+# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinOtherProgramFiles, "ProgramFiles(x86)", RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinOtherCommonProgramFiles, "CommonProgramFiles(x86)", RTPATH_MAX);
+# else
+# error "Port ME!"
+# endif
+static const char * const a_apszWinProgramFilesVars[] =
+{
+ "ProgramFiles",
+# ifdef RT_ARCH_AMD64
+ "ProgramFiles(x86)",
+# endif
+};
+RTPATHMATCHVAR_MULTIPLE_ENVVARS(WinAllProgramFiles, a_apszWinProgramFilesVars, RTPATH_MAX);
+static const char * const a_apszWinCommonProgramFilesVars[] =
+{
+ "CommonProgramFiles",
+# ifdef RT_ARCH_AMD64
+ "CommonProgramFiles(x86)",
+# endif
+};
+RTPATHMATCHVAR_MULTIPLE_ENVVARS(WinAllCommonProgramFiles, a_apszWinCommonProgramFilesVars, RTPATH_MAX);
+#endif
+
+
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery, Enumerates the PATH}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_Path(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+ PRTPATHMATCHCACHE pCache)
+{
+ /*
+ * Query the PATH value.
+ */
+/** @todo cache this in pCache with iItem and offset. */
+ char *pszPathFree = NULL;
+ char *pszPath = pszBuf;
+ size_t cchActual;
+ const char *pszVarNm = "PATH";
+ int rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm, pszPath, cbBuf, &cchActual);
+#ifdef RT_OS_WINDOWS
+ if (rc == VERR_ENV_VAR_NOT_FOUND)
+ rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm = "Path", pszPath, cbBuf, &cchActual);
+#endif
+ if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ for (uint32_t iTry = 0; iTry < 10; iTry++)
+ {
+ size_t cbPathBuf = RT_ALIGN_Z(cchActual + 1 + 64 * iTry, 64);
+ pszPathFree = (char *)RTMemTmpAlloc(cbPathBuf);
+ rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm, pszPathFree, cbPathBuf, &cchActual);
+ if (RT_SUCCESS(rc))
+ break;
+ RTMemTmpFree(pszPathFree);
+ AssertReturn(cchActual >= cbPathBuf, VERR_INTERNAL_ERROR_3);
+ }
+ pszPath = pszPathFree;
+ }
+
+ /*
+ * Spool forward to the given PATH item.
+ */
+ rc = VERR_EOF;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ const char chSep = ';';
+#else
+ const char chSep = ':';
+#endif
+ while (*pszPath != '\0')
+ {
+ char *pchSep = strchr(pszPath, chSep);
+
+ /* We ignore empty strings, which is probably not entirely correct,
+ but works better on DOS based system with many entries added
+ without checking whether there is a trailing separator or not.
+ Thus, the current directory is only searched if a '.' is present
+ in the PATH. */
+ if (pchSep == pszPath)
+ pszPath++;
+ else if (iItem > 0)
+ {
+ /* If we didn't find a separator, the item doesn't exists. Quit. */
+ if (!pchSep)
+ break;
+
+ pszPath = pchSep + 1;
+ iItem--;
+ }
+ else
+ {
+ /* We've reached the item we wanted. */
+ size_t cchComp = pchSep ? pchSep - pszPath : strlen(pszPath);
+ if (cchComp < cbBuf)
+ {
+ if (pszBuf != pszPath)
+ memmove(pszBuf, pszPath, cchComp);
+ pszBuf[cchComp] = '\0';
+ rc = pchSep ? VINF_SUCCESS : VINF_EOF;
+ }
+ else
+ rc = VERR_BUFFER_OVERFLOW;
+ *pcchValue = cchComp;
+ break;
+ }
+ }
+
+ if (pszPathFree)
+ RTMemTmpFree(pszPathFree);
+ return rc;
+}
+
+
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery,
+ * The system drive letter + colon.}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_DosSystemDrive(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+ PRTPATHMATCHCACHE pCache)
+{
+ if (iItem == 0)
+ {
+ AssertReturn(cbBuf >= 3, VERR_BUFFER_OVERFLOW);
+
+# ifdef RT_OS_WINDOWS
+ /* Since this is used at the start of a pattern, we assume
+ we've got more than enough buffer space. */
+ PRTUTF16 pwszTmp = (PRTUTF16)pszBuf;
+ UINT cch = GetSystemWindowsDirectoryW(pwszTmp, (UINT)(cbBuf / sizeof(WCHAR)));
+ if (cch >= 2)
+ {
+ RTUTF16 wcDrive = pwszTmp[0];
+ if ( RT_C_IS_ALPHA(wcDrive)
+ && pwszTmp[1] == ':')
+ {
+ pszBuf[0] = wcDrive;
+ pszBuf[1] = ':';
+ pszBuf[2] = '\0';
+ *pcchValue = 2;
+ return VINF_EOF;
+ }
+ }
+# else
+ ULONG ulDrive = ~(ULONG)0;
+ APIRET rc = DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulDrive, sizeof(ulDrive));
+ ulDrive--; /* 1 = 'A' */
+ if ( rc == NO_ERROR
+ && ulDrive <= (ULONG)'Z')
+ {
+ pszBuf[0] = (char)ulDrive + 'A';
+ pszBuf[1] = ':';
+ pszBuf[2] = '\0';
+ *pcchValue = 2;
+ return VINF_EOF;
+ }
+# endif
+ return VERR_INTERNAL_ERROR_4;
+ }
+ return VERR_EOF;
+}
+#endif
+
+
+#ifdef RT_OS_WINDOWS
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery,
+ * The system root directory (C:\Windows).}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_WinSystemRoot(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+ PRTPATHMATCHCACHE pCache)
+{
+ if (iItem == 0)
+ {
+ Assert(pszBuf); Assert(cbBuf);
+ RTUTF16 wszSystemRoot[MAX_PATH];
+ UINT cchSystemRoot = GetSystemWindowsDirectoryW(wszSystemRoot, MAX_PATH);
+ if (cchSystemRoot > 0)
+ return RTUtf16ToUtf8Ex(wszSystemRoot, cchSystemRoot, &pszBuf, cbBuf, pcchValue);
+ return RTErrConvertFromWin32(GetLastError());
+ }
+ return VERR_EOF;
+}
+#endif
+
+#undef RTPATHMATCHVAR_SIMPLE
+#undef RTPATHMATCHVAR_SIMPLE_ENVVAR
+#undef RTPATHMATCHVAR_DOUBLE_ENVVAR
+
+/**
+ * Matching variable lookup table.
+ * Currently so small we don't bother sorting it and doing binary lookups.
+ */
+static struct RTPATHMATCHVAR
+{
+ /** The variable name. */
+ const char *pszName;
+ /** The variable name length. */
+ uint16_t cchName;
+ /** Only available as the verify first component. */
+ bool fFirstOnly;
+
+ /**
+ * Queries a given variable value.
+ *
+ * @returns IPRT status code.
+ * @retval VERR_BUFFER_OVERFLOW
+ * @retval VERR_TRY_AGAIN if the caller should skip this value item and try the
+ * next one instead (e.g. env var not present).
+ * @retval VINF_EOF when retrieving the last one, if possible.
+ * @retval VERR_EOF when @a iItem is past the item space.
+ *
+ * @param iItem The variable value item to retrieve. (A variable may
+ * have more than one value, e.g. 'BothProgramFile' on a
+ * 64-bit system or 'Path'.)
+ * @param pszBuf Where to return the value.
+ * @param cbBuf The buffer size.
+ * @param pcchValue Where to return the length of the return string.
+ * @param pCache Pointer to the path matching cache. May speed up
+ * enumerating PATH items and similar.
+ */
+ DECLCALLBACKMEMBER(int, pfnQuery)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, PRTPATHMATCHCACHE pCache);
+
+ /**
+ * Matching method, optional.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_SUCCESS on match.
+ * @retval VERR_MISMATCH on mismatch.
+ *
+ * @param pszMatch String to match with (not terminated).
+ * @param cchMatch The length of what we match with.
+ * @param fIgnoreCase Whether to ignore case or not when comparing.
+ * @param pcchMatched Where to return the length of the match (value length).
+ */
+ DECLCALLBACKMEMBER(int, pfnMatch)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, size_t *pcchMatched);
+
+} const g_aVariables[] =
+{
+ { RT_STR_TUPLE("Arch"), false, rtPathVarQuery_Arch, rtPathVarMatch_Arch },
+ { RT_STR_TUPLE("Bits"), false, rtPathVarQuery_Bits, rtPathVarMatch_Bits },
+ { RT_STR_TUPLE("Path"), true, rtPathVarQuery_Path, NULL },
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ { RT_STR_TUPLE("SystemDrive"), true, rtPathVarQuery_DosSystemDrive, NULL },
+#endif
+#ifdef RT_OS_WINDOWS
+ { RT_STR_TUPLE("SystemRoot"), true, rtPathVarQuery_WinSystemRoot, NULL },
+ { RT_STR_TUPLE("AppData"), true, rtPathVarQuery_WinAppData, NULL },
+ { RT_STR_TUPLE("ProgramData"), true, rtPathVarQuery_WinProgramData, NULL },
+ { RT_STR_TUPLE("ProgramFiles"), true, rtPathVarQuery_WinProgramFiles, NULL },
+ { RT_STR_TUPLE("OtherProgramFiles"), true, rtPathVarQuery_WinOtherProgramFiles, NULL },
+ { RT_STR_TUPLE("AllProgramFiles"), true, rtPathVarQuery_WinAllProgramFiles, NULL },
+ { RT_STR_TUPLE("CommonProgramFiles"), true, rtPathVarQuery_WinCommonProgramFiles, NULL },
+ { RT_STR_TUPLE("OtherCommonProgramFiles"), true, rtPathVarQuery_WinOtherCommonProgramFiles, NULL },
+ { RT_STR_TUPLE("AllCommonProgramFiles"), true, rtPathVarQuery_WinAllCommonProgramFiles, NULL },
+#endif
+};
+
+
+
+/**
+ * Handles a complicated set.
+ *
+ * A complicated set is either using ranges, character classes or code points
+ * outside the ASCII-7 range.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH. May also return UTF-8 decoding
+ * errors as well as VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED.
+ *
+ * @param ucInput The input code point to match with.
+ * @param pchSet The start of the set specification (after caret).
+ * @param cchSet The length of the set specification.
+ */
+static int rtPathMatchExecExtendedSet(RTUNICP ucInput, const char *pchSet, size_t cchSet)
+{
+ while (cchSet > 0)
+ {
+ RTUNICP ucSet;
+ int rc = RTStrGetCpNEx(&pchSet, &cchSet, &ucSet);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Check for character class, collating symbol and equvalence class.
+ */
+ if (ucSet == '[' && cchSet > 0)
+ {
+ char chNext = *pchSet;
+ if (chNext == ':')
+ {
+#define CHECK_CHAR_CLASS(a_szClassNm, a_BoolTestExpr) \
+ if ( cchSet >= sizeof(a_szClassNm) \
+ && memcmp(pchSet, a_szClassNm "]", sizeof(a_szClassNm)) == 0) \
+ { \
+ if (a_BoolTestExpr) \
+ return VINF_SUCCESS; \
+ pchSet += sizeof(a_szClassNm); \
+ cchSet -= sizeof(a_szClassNm); \
+ continue; \
+ } do { } while (0)
+
+ CHECK_CHAR_CLASS(":alpha:", RTUniCpIsAlphabetic(ucInput));
+ CHECK_CHAR_CLASS(":alnum:", RTUniCpIsAlphabetic(ucInput) || RTUniCpIsDecDigit(ucInput)); /** @todo figure what's correct here and fix uni.h */
+ CHECK_CHAR_CLASS(":blank:", ucInput == ' ' || ucInput == '\t');
+ CHECK_CHAR_CLASS(":cntrl:", ucInput < 31 || ucInput == 127);
+ CHECK_CHAR_CLASS(":digit:", RTUniCpIsDecDigit(ucInput));
+ CHECK_CHAR_CLASS(":lower:", RTUniCpIsLower(ucInput));
+ CHECK_CHAR_CLASS(":print:", RTUniCpIsAlphabetic(ucInput) || (RT_C_IS_PRINT(ucInput) && ucInput < 127)); /** @todo fixme*/
+ CHECK_CHAR_CLASS(":punct:", RT_C_IS_PRINT(ucInput) && ucInput < 127); /** @todo fixme*/
+ CHECK_CHAR_CLASS(":space:", RTUniCpIsSpace(ucInput));
+ CHECK_CHAR_CLASS(":upper:", RTUniCpIsUpper(ucInput));
+ CHECK_CHAR_CLASS(":xdigit:", RTUniCpIsHexDigit(ucInput));
+ AssertMsgFailedReturn(("Unknown or malformed char class: '%.*s'\n", cchSet + 1, pchSet - 1),
+ VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS);
+#undef CHECK_CHAR_CLASS
+ }
+ /** @todo implement collating symbol and equvalence class. */
+ else if (chNext == '=' || chNext == '.')
+ AssertFailedReturn(VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED);
+ }
+
+ /*
+ * Check for range (leading or final dash does not constitute a range).
+ */
+ if (cchSet > 1 && *pchSet == '-')
+ {
+ pchSet++; /* skip dash */
+ cchSet--;
+
+ RTUNICP ucSet2;
+ rc = RTStrGetCpNEx(&pchSet, &cchSet, &ucSet2);
+ AssertRCReturn(rc, rc);
+ Assert(ucSet < ucSet2);
+ if (ucInput >= ucSet && ucInput <= ucSet2)
+ return VINF_SUCCESS;
+ }
+ /*
+ * Single char comparison.
+ */
+ else if (ucInput == ucSet)
+ return VINF_SUCCESS;
+ }
+ return VERR_MISMATCH;
+}
+
+
+/**
+ * Variable matching fallback using the query function.
+ *
+ * This must not be inlined as it consuming a lot of stack! Which is why it's
+ * placed a couple of functions away from the recursive rtPathExecMatch.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param pchInput The current input position.
+ * @param cchInput The amount of input left..
+ * @param idxVar The variable table index.
+ * @param fIgnoreCase Whether to ignore case when comparing.
+ * @param pcchMatched Where to return how much we actually matched up.
+ * @param pCache Pointer to the path matching cache.
+ */
+DECL_NO_INLINE(static, int) rtPathMatchExecVariableFallback(const char *pchInput, size_t cchInput, uint16_t idxVar,
+ bool fIgnoreCase, size_t *pcchMatched, PRTPATHMATCHCACHE pCache)
+{
+ for (uint32_t iItem = 0; iItem < RTPATHMATCH_MAX_VAR_ITEMS; iItem++)
+ {
+ char szValue[RTPATH_MAX];
+ size_t cchValue;
+ int rc = g_aVariables[idxVar].pfnQuery(iItem, szValue, sizeof(szValue), &cchValue, pCache);
+ if (RT_SUCCESS(rc))
+ {
+ if (cchValue <= cchInput)
+ {
+ if ( !fIgnoreCase
+ ? memcmp(pchInput, szValue, cchValue) == 0
+ : RTStrNICmp(pchInput, szValue, cchValue) == 0)
+ {
+ *pcchMatched = cchValue;
+ return VINF_SUCCESS;
+ }
+ }
+ if (rc == VINF_EOF)
+ return VERR_MISMATCH;
+ }
+ else if (rc == VERR_EOF)
+ return VERR_MISMATCH;
+ else
+ Assert(rc == VERR_BUFFER_OVERFLOW || rc == VERR_TRY_AGAIN);
+ }
+ AssertFailed();
+ return VERR_MISMATCH;
+}
+
+
+/**
+ * Variable matching worker.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param pchInput The current input position.
+ * @param cchInput The amount of input left..
+ * @param idxVar The variable table index.
+ * @param fIgnoreCase Whether to ignore case when comparing.
+ * @param pcchMatched Where to return how much we actually matched up.
+ * @param pCache Pointer to the path matching cache.
+ */
+static int rtPathMatchExecVariable(const char *pchInput, size_t cchInput, uint16_t idxVar,
+ bool fIgnoreCase, size_t *pcchMatched, PRTPATHMATCHCACHE pCache)
+{
+ Assert(idxVar < RT_ELEMENTS(g_aVariables));
+ if (g_aVariables[idxVar].pfnMatch)
+ return g_aVariables[idxVar].pfnMatch(pchInput, cchInput, fIgnoreCase, pcchMatched);
+ return rtPathMatchExecVariableFallback(pchInput, cchInput, idxVar, fIgnoreCase, pcchMatched, pCache);
+}
+
+
+/**
+ * Variable matching worker.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param pchInput The current input position.
+ * @param cchInput The amount of input left..
+ * @param pProg The first matching program instruction.
+ * @param pCache Pointer to the path matching cache.
+ */
+static int rtPathMatchExec(const char *pchInput, size_t cchInput, PCRTPATHMATCHCORE pProg, PRTPATHMATCHCACHE pCache)
+{
+ for (;;)
+ {
+ switch (pProg->enmOpCode)
+ {
+ case RTPATHMATCHOP_RETURN_MATCH_IF_AT_END:
+ return cchInput == 0 ? VINF_SUCCESS : VERR_MISMATCH;
+
+ case RTPATHMATCHOP_RETURN_MATCH:
+ return VINF_SUCCESS;
+
+ case RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT:
+ if ( cchInput > 2
+ || cchInput < 1
+ || pchInput[0] != '.'
+ || (cchInput == 2 && pchInput[1] != '.') )
+ return VINF_SUCCESS;
+ return VERR_MISMATCH;
+
+ case RTPATHMATCHOP_STRCMP:
+ if (pProg->cch > cchInput)
+ return VERR_MISMATCH;
+ if (memcmp(pchInput, pProg->pch, pProg->cch) != 0)
+ return VERR_MISMATCH;
+ cchInput -= pProg->cch;
+ pchInput += pProg->cch;
+ break;
+
+ case RTPATHMATCHOP_STRICMP:
+ if (pProg->cch > cchInput)
+ return VERR_MISMATCH;
+ if (RTStrNICmp(pchInput, pProg->pch, pProg->cch) != 0)
+ return VERR_MISMATCH;
+ cchInput -= pProg->cch;
+ pchInput += pProg->cch;
+ break;
+
+ case RTPATHMATCHOP_SKIP_ONE_CODEPOINT:
+ {
+ if (cchInput == 0)
+ return VERR_MISMATCH;
+ RTUNICP ucInputIgnore;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInputIgnore);
+ AssertRCReturn(rc, rc);
+ break;
+ }
+
+ case RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS:
+ {
+ uint16_t cCpsLeft = pProg->cch;
+ Assert(cCpsLeft > 1);
+ if (cCpsLeft > cchInput)
+ return VERR_MISMATCH;
+ while (cCpsLeft-- > 0)
+ {
+ RTUNICP ucInputIgnore;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInputIgnore);
+ if (RT_FAILURE(rc))
+ return rc == VERR_END_OF_STRING ? VERR_MISMATCH : rc;
+ }
+ break;
+ }
+
+ case RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7:
+ {
+ if (cchInput == 0)
+ return VERR_MISMATCH;
+ RTUNICP ucInput;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+ AssertRCReturn(rc, rc);
+ if (ucInput >= 0x80)
+ return VERR_MISMATCH;
+ if (memchr(pProg->pch, (char)ucInput, pProg->cch) == NULL)
+ return VERR_MISMATCH;
+ break;
+ }
+
+ case RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7:
+ {
+ if (cchInput == 0)
+ return VERR_MISMATCH;
+ RTUNICP ucInput;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+ AssertRCReturn(rc, rc);
+ if (ucInput >= 0x80)
+ break;
+ if (memchr(pProg->pch, (char)ucInput, pProg->cch) != NULL)
+ return VERR_MISMATCH;
+ break;
+ }
+
+ case RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED:
+ {
+ if (cchInput == 0)
+ return VERR_MISMATCH;
+ RTUNICP ucInput;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+ AssertRCReturn(rc, rc);
+ rc = rtPathMatchExecExtendedSet(ucInput, pProg->pch, pProg->cch);
+ if (rc == VINF_SUCCESS)
+ break;
+ return rc;
+ }
+
+ case RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED:
+ {
+ if (cchInput == 0)
+ return VERR_MISMATCH;
+ RTUNICP ucInput;
+ int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+ AssertRCReturn(rc, rc);
+ rc = rtPathMatchExecExtendedSet(ucInput, pProg->pch, pProg->cch);
+ if (rc == VERR_MISMATCH)
+ break;
+ if (rc == VINF_SUCCESS)
+ rc = VERR_MISMATCH;
+ return rc;
+ }
+
+ case RTPATHMATCHOP_VARIABLE_VALUE_CMP:
+ case RTPATHMATCHOP_VARIABLE_VALUE_ICMP:
+ {
+ size_t cchMatched = 0;
+ int rc = rtPathMatchExecVariable(pchInput, cchInput, pProg->uOp2,
+ pProg->enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_ICMP, &cchMatched, pCache);
+ if (rc == VINF_SUCCESS)
+ {
+ pchInput += cchMatched;
+ cchInput -= cchMatched;
+ break;
+ }
+ return rc;
+ }
+
+ /*
+ * This is the expensive one. It always completes the program.
+ */
+ case RTPATHMATCHOP_ZERO_OR_MORE:
+ {
+ if (cchInput < pProg->cch)
+ return VERR_MISMATCH;
+ size_t cchMatched = cchInput - pProg->cch;
+ do
+ {
+ int rc = rtPathMatchExec(&pchInput[cchMatched], cchInput - cchMatched, pProg + 1, pCache);
+ if (RT_SUCCESS(rc))
+ return rc;
+ } while (cchMatched-- > 0);
+ return VERR_MISMATCH;
+ }
+
+ /*
+ * Variant of the above that doesn't match '.' and '..' entries.
+ */
+ case RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT:
+ {
+ if (cchInput < pProg->cch)
+ return VERR_MISMATCH;
+ if ( cchInput <= 2
+ && cchInput > 0
+ && pchInput[0] == '.'
+ && (cchInput == 1 || pchInput[1] == '.') )
+ return VERR_MISMATCH;
+ size_t cchMatched = cchInput - pProg->cch;
+ do
+ {
+ int rc = rtPathMatchExec(&pchInput[cchMatched], cchInput - cchMatched, pProg + 1, pCache);
+ if (RT_SUCCESS(rc))
+ return rc;
+ } while (cchMatched-- > 0);
+ return VERR_MISMATCH;
+ }
+
+ default:
+ AssertMsgFailedReturn(("enmOpCode=%d\n", pProg->enmOpCode), VERR_INTERNAL_ERROR_3);
+ }
+
+ pProg++;
+ }
+}
+
+
+
+
+/**
+ * Compiles a path matching program.
+ *
+ * @returns IPRT status code.
+ * @param pchPattern The pattern to compile.
+ * @param cchPattern The length of the pattern.
+ * @param pAllocator Pointer to the instruction allocator & result
+ * array. The compiled "program" starts at
+ * PRTPATHMATCHALLOC::paInstructions[PRTPATHMATCHALLOC::iNext]
+ * (input iNext value).
+ *
+ * @todo Expose this matching code and also use it for RTDirOpenFiltered
+ */
+static int rtPathMatchCompile(const char *pchPattern, size_t cchPattern, bool fIgnoreCase, PRTPATHMATCHALLOC pAllocator)
+{
+ /** @todo PORTME: big endian. */
+ static const uint8_t s_bmMetaChars[256/8] =
+ {
+ 0x00, 0x00, 0x00, 0x00, /* 0 thru 31 */
+ 0x10, 0x04, 0x00, 0x80, /* 32 thru 63 */
+ 0x00, 0x00, 0x00, 0x08, /* 64 thru 95 */
+ 0x00, 0x00, 0x00, 0x00, /* 96 thru 127 */
+ /* UTF-8 multibyte: */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ Assert(ASMBitTest(s_bmMetaChars, '$')); AssertCompile('$' == 0x24 /*36*/);
+ Assert(ASMBitTest(s_bmMetaChars, '*')); AssertCompile('*' == 0x2a /*42*/);
+ Assert(ASMBitTest(s_bmMetaChars, '?')); AssertCompile('?' == 0x3f /*63*/);
+ Assert(ASMBitTest(s_bmMetaChars, '[')); AssertCompile('[' == 0x5b /*91*/);
+
+ /*
+ * For checking for the first instruction.
+ */
+ uint16_t const iFirst = pAllocator->iNext;
+
+ /*
+ * This is for tracking zero-or-more instructions and for calculating
+ * the minimum amount of input required for it to be considered.
+ */
+ uint16_t aiZeroOrMore[RTPATHMATCH_MAX_ZERO_OR_MORE];
+ uint8_t cZeroOrMore = 0;
+ size_t offInput = 0;
+
+ /*
+ * Loop thru the pattern and translate it into string matching instructions.
+ */
+ for (;;)
+ {
+ /*
+ * Allocate the next instruction.
+ */
+ if (pAllocator->iNext >= pAllocator->cAllocated)
+ {
+ uint32_t cNew = pAllocator->cAllocated ? pAllocator->cAllocated * 2 : 2;
+ void *pvNew = RTMemRealloc(pAllocator->paInstructions, cNew * sizeof(pAllocator->paInstructions[0]));
+ AssertReturn(pvNew, VERR_NO_MEMORY);
+ pAllocator->paInstructions = (PRTPATHMATCHCORE)pvNew;
+ pAllocator->cAllocated = cNew;
+ }
+ PRTPATHMATCHCORE pInstr = &pAllocator->paInstructions[pAllocator->iNext++];
+ pInstr->pch = pchPattern;
+ pInstr->cch = 0;
+ pInstr->uOp2 = 0;
+
+ /*
+ * Special case: End of pattern.
+ */
+ if (!cchPattern)
+ {
+ pInstr->enmOpCode = RTPATHMATCHOP_RETURN_MATCH_IF_AT_END;
+ break;
+ }
+
+ /*
+ * Parse the next bit of the pattern.
+ */
+ char ch = *pchPattern;
+ if (ASMBitTest(s_bmMetaChars, (uint8_t)ch))
+ {
+ /*
+ * Zero or more characters wildcard.
+ */
+ if (ch == '*')
+ {
+ /* Skip extra asterisks. */
+ do
+ {
+ cchPattern--;
+ pchPattern++;
+ } while (cchPattern > 0 && *pchPattern == '*');
+
+ /* There is a special optimization for trailing '*'. */
+ pInstr->cch = 1;
+ if (cchPattern == 0)
+ {
+ pInstr->enmOpCode = iFirst + 1U == pAllocator->iNext
+ ? RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT : RTPATHMATCHOP_RETURN_MATCH;
+ break;
+ }
+
+ pInstr->enmOpCode = iFirst + 1U == pAllocator->iNext
+ ? RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT : RTPATHMATCHOP_ZERO_OR_MORE;
+ pInstr->uOp2 = (uint16_t)offInput;
+ AssertReturn(cZeroOrMore < RT_ELEMENTS(aiZeroOrMore), VERR_OUT_OF_RANGE);
+ aiZeroOrMore[cZeroOrMore] = (uint16_t)(pInstr - pAllocator->paInstructions);
+
+ /* cchInput unchanged, zero-or-more matches. */
+ continue;
+ }
+
+ /*
+ * Single character wildcard.
+ */
+ if (ch == '?')
+ {
+ /* Count them if more. */
+ uint16_t cchQms = 1;
+ while (cchQms < cchPattern && pchPattern[cchQms] == '?')
+ cchQms++;
+
+ pInstr->cch = cchQms;
+ pInstr->enmOpCode = cchQms == 1 ? RTPATHMATCHOP_SKIP_ONE_CODEPOINT : RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS;
+
+ cchPattern -= cchQms;
+ pchPattern += cchQms;
+ offInput += cchQms;
+ continue;
+ }
+
+ /*
+ * Character in set.
+ *
+ * Note that we skip the first char in the set as that is the only place
+ * ']' can be placed if one desires to explicitly include it in the set.
+ * To make life a bit more interesting, [:class:] is allowed inside the
+ * set, so we have to do the counting game to find the end.
+ */
+ if (ch == '[')
+ {
+ if ( cchPattern > 2
+ && (const char *)memchr(pchPattern + 2, ']', cchPattern) != NULL)
+ {
+
+ /* Check for not-in. */
+ bool fInverted = false;
+ size_t offStart = 1;
+ if (pchPattern[offStart] == '^')
+ {
+ fInverted = true;
+ offStart++;
+ }
+
+ /* Special case for ']' as the first char, it doesn't indicate closing then. */
+ size_t off = offStart;
+ if (pchPattern[off] == ']')
+ off++;
+
+ bool fExtended = false;
+ while (off < cchPattern)
+ {
+ ch = pchPattern[off++];
+ if (ch == '[')
+ {
+ if (off < cchPattern)
+ {
+ char chOpen = pchPattern[off];
+ if ( chOpen == ':'
+ || chOpen == '='
+ || chOpen == '.')
+ {
+ off++;
+ const char *pchFound = (const char *)memchr(&pchPattern[off], ']', cchPattern - off);
+ if ( pchFound
+ && pchFound[-1] == chOpen)
+ {
+ fExtended = true;
+ off = pchFound - pchPattern + 1;
+ }
+ else
+ AssertFailed();
+ }
+ }
+ }
+ /* Check for closing. */
+ else if (ch == ']')
+ break;
+ /* Check for range expression, promote to extended if this happens. */
+ else if ( ch == '-'
+ && off != offStart + 1
+ && off < cchPattern
+ && pchPattern[off] != ']')
+ fExtended = true;
+ /* UTF-8 multibyte chars forces us to use the extended version too. */
+ else if ((uint8_t)ch >= 0x80)
+ fExtended = true;
+ }
+
+ if (ch == ']')
+ {
+ pInstr->pch = &pchPattern[offStart];
+ pInstr->cch = (uint16_t)(off - offStart - 1);
+ if (!fExtended)
+ pInstr->enmOpCode = !fInverted
+ ? RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7 : RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7;
+ else
+ pInstr->enmOpCode = !fInverted
+ ? RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED
+ : RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED;
+ pchPattern += off;
+ cchPattern -= off;
+ offInput += 1;
+ continue;
+ }
+
+ /* else: invalid, treat it as */
+ AssertFailed();
+ }
+ }
+ /*
+ * Variable matching.
+ */
+ else if (ch == '$')
+ {
+ const char *pchFound;
+ if ( cchPattern > 3
+ && pchPattern[1] == '{'
+ && (pchFound = (const char *)memchr(pchPattern + 2, '}', cchPattern)) != NULL
+ && pchFound != &pchPattern[2])
+ {
+ /* skip to the variable name. */
+ pchPattern += 2;
+ cchPattern -= 2;
+ size_t cchVarNm = pchFound - pchPattern;
+
+ /* Look it up. */
+ uint32_t iVar;
+ for (iVar = 0; iVar < RT_ELEMENTS(g_aVariables); iVar++)
+ if ( g_aVariables[iVar].cchName == cchVarNm
+ && memcmp(g_aVariables[iVar].pszName, pchPattern, cchVarNm) == 0)
+ break;
+ if (iVar < RT_ELEMENTS(g_aVariables))
+ {
+ pInstr->uOp2 = (uint16_t)iVar;
+ pInstr->enmOpCode = !fIgnoreCase ? RTPATHMATCHOP_VARIABLE_VALUE_CMP : RTPATHMATCHOP_VARIABLE_VALUE_ICMP;
+ pInstr->pch = pchPattern; /* not necessary */
+ pInstr->cch = (uint16_t)cchPattern; /* ditto */
+ pchPattern += cchVarNm + 1;
+ cchPattern -= cchVarNm + 1;
+ AssertMsgReturn(!g_aVariables[iVar].fFirstOnly || iFirst + 1U == pAllocator->iNext,
+ ("Glob variable '%s' should be first\n", g_aVariables[iVar].pszName),
+ VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST);
+ /* cchInput unchanged, value can be empty. */
+ continue;
+ }
+ AssertMsgFailedReturn(("Unknown path matching variable '%.*s'\n", cchVarNm, pchPattern),
+ VERR_PATH_MATCH_UNKNOWN_VARIABLE);
+ }
+ }
+ else
+ AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* broken bitmap / compiler codeset */
+ }
+
+ /*
+ * Plain text. Look for the next meta char.
+ */
+ uint32_t cchPlain = 1;
+ while (cchPlain < cchPattern)
+ {
+ ch = pchPattern[cchPlain];
+ if (!ASMBitTest(s_bmMetaChars, (uint8_t)ch))
+ { /* probable */ }
+ else if ( ch == '?'
+ || ch == '*')
+ break;
+ else if (ch == '$')
+ {
+ const char *pchFound;
+ if ( cchPattern > cchPlain + 3
+ && pchPattern[cchPlain + 1] == '{'
+ && (pchFound = (const char *)memchr(&pchPattern[cchPlain + 2], '}', cchPattern - cchPlain - 2)) != NULL
+ && pchFound != &pchPattern[cchPlain + 2])
+ break;
+ }
+ else if (ch == '[')
+ {
+ /* We don't put a lot of effort into getting this 100% right here,
+ no point it complicating things for malformed expressions. */
+ if ( cchPattern > cchPlain + 2
+ && memchr(&pchPattern[cchPlain + 2], ']', cchPattern - cchPlain - 1) != NULL)
+ break;
+ }
+ else
+ AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* broken bitmap / compiler codeset */
+ cchPlain++;
+ }
+ pInstr->enmOpCode = !fIgnoreCase ? RTPATHMATCHOP_STRCMP : RTPATHMATCHOP_STRICMP;
+ pInstr->cch = cchPlain;
+ Assert(pInstr->pch == pchPattern);
+ Assert(pInstr->uOp2 == 0);
+ pchPattern += cchPlain;
+ cchPattern -= cchPlain;
+ offInput += cchPlain;
+ }
+
+ /*
+ * Optimize zero-or-more matching.
+ */
+ while (cZeroOrMore-- > 0)
+ {
+ PRTPATHMATCHCORE pInstr = &pAllocator->paInstructions[aiZeroOrMore[cZeroOrMore]];
+ pInstr->uOp2 = (uint16_t)(offInput - pInstr->uOp2);
+ }
+
+ /** @todo It's possible to use offInput to inject a instruction for checking
+ * minimum input length at the start of the program. Not sure it's
+ * worth it though, unless it's long a complicated expression... */
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Parses the glob pattern.
+ *
+ * This compiles filename matching programs for each component and determins the
+ * optimal search strategy for them.
+ *
+ * @returns IPRT status code.
+ * @param pGlob The glob instance data.
+ * @param pszPattern The pattern to parse.
+ * @param pParsed The RTPathParse output for the pattern.
+ * @param fFlags The glob flags (same as pGlob->fFlags).
+ */
+static int rtPathGlobParse(PRTPATHGLOB pGlob, const char *pszPattern, PRTPATHPARSED pParsed, uint32_t fFlags)
+{
+ AssertReturn(pParsed->cComps > 0, VERR_INVALID_PARAMETER); /* shouldn't happen */
+ uint32_t iComp = 0;
+
+ /*
+ * If we've got a rootspec, mark it as plain. On platforms with
+ * drive letter and/or UNC we don't allow wildcards or such in
+ * the drive letter spec or UNC server name. (At least not yet.)
+ */
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
+ {
+ AssertReturn(pParsed->aComps[0].cch < sizeof(pGlob->szPath) - 1, VERR_FILENAME_TOO_LONG);
+ memcpy(pGlob->szPath, &pszPattern[pParsed->aComps[0].off], pParsed->aComps[0].cch);
+ pGlob->offFirstPath = pParsed->aComps[0].cch;
+ pGlob->iFirstComp = iComp = 1;
+ }
+ else
+ {
+ const char * const pszComp = &pszPattern[pParsed->aComps[0].off];
+
+ /*
+ * The tilde is only applicable to the first component, expand it
+ * immediately.
+ */
+ if ( *pszComp == '~'
+ && !(fFlags & RTPATHGLOB_F_NO_TILDE))
+ {
+ if (pParsed->aComps[0].cch == 1)
+ {
+ int rc = RTPathUserHome(pGlob->szPath, sizeof(pGlob->szPath) - 1);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ AssertMsgFailedReturn(("'%.*s' is not supported yet\n", pszComp, pParsed->aComps[0].cch),
+ VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED);
+ pGlob->offFirstPath = (uint32_t)RTPathEnsureTrailingSeparator(pGlob->szPath, sizeof(pGlob->szPath));
+ pGlob->iFirstComp = iComp = 1;
+ }
+ }
+
+ /*
+ * Process the other components.
+ */
+ bool fStarStar = false;
+ for (; iComp < pParsed->cComps; iComp++)
+ {
+ const char *pszComp = &pszPattern[pParsed->aComps[iComp].off];
+ uint16_t cchComp = pParsed->aComps[iComp].cch;
+ Assert(pGlob->aComps[iComp].fNormal == false);
+
+ pGlob->aComps[iComp].fDir = iComp + 1 < pParsed->cComps || (fFlags & RTPATHGLOB_F_ONLY_DIRS);
+ if ( cchComp != 2
+ || pszComp[0] != '*'
+ || pszComp[1] != '*'
+ || (fFlags & RTPATHGLOB_F_NO_STARSTAR) )
+ {
+ /* Compile the pattern. */
+ uint16_t const iMatchProg = pGlob->MatchInstrAlloc.iNext;
+ pGlob->aComps[iComp].iMatchProg = iMatchProg;
+ int rc = rtPathMatchCompile(pszComp, cchComp, RT_BOOL(fFlags & RTPATHGLOB_F_IGNORE_CASE),
+ &pGlob->MatchInstrAlloc);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Check for plain text as well as full variable matching (not applicable after '**'). */
+ uint16_t const cInstructions = pGlob->MatchInstrAlloc.iNext - iMatchProg;
+ if ( cInstructions == 2
+ && !fStarStar
+ && pGlob->MatchInstrAlloc.paInstructions[iMatchProg + 1].enmOpCode == RTPATHMATCHOP_RETURN_MATCH_IF_AT_END)
+ {
+ if ( pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_STRCMP
+ || pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_STRICMP)
+ pGlob->aComps[iComp].fPlain = true;
+ else if ( pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_CMP
+ || pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_ICMP)
+ {
+ pGlob->aComps[iComp].fExpVariable = true;
+ AssertMsgReturn( iComp == 0
+ || !g_aVariables[pGlob->MatchInstrAlloc.paInstructions[iMatchProg].uOp2].fFirstOnly,
+ ("Glob variable '%.*s' can only be used as the path component.\n", cchComp, pszComp),
+ VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST);
+ }
+ else
+ pGlob->aComps[iComp].fNormal = true;
+ }
+ else
+ pGlob->aComps[iComp].fNormal = true;
+ }
+ else
+ {
+ /* Recursive "**" matching. */
+ pGlob->aComps[iComp].fNormal = false;
+ pGlob->aComps[iComp].fStarStar = true;
+ AssertReturn(!fStarStar, VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED); /** @todo implement multiple '**' sequences in a pattern. */
+ fStarStar = true;
+ }
+ }
+ pGlob->aComps[pParsed->cComps - 1].fFinal = true;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * This is for skipping overly long directories entries.
+ *
+ * Since our directory entry buffer can hold filenames of RTPATH_MAX bytes, we
+ * can safely skip filenames that are longer. There are very few file systems
+ * that can actually store filenames longer than 255 bytes at time of coding
+ * (2015-09), and extremely few which can exceed 4096 (RTPATH_MAX) bytes.
+ *
+ * @returns IPRT status code.
+ * @param hDir The directory handle.
+ * @param cbNeeded The required entry size.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobSkipDirEntry(PRTDIR hDir, size_t cbNeeded)
+{
+ int rc = VERR_BUFFER_OVERFLOW;
+ cbNeeded = RT_ALIGN_Z(cbNeeded, 16);
+ PRTDIRENTRY pDirEntry = (PRTDIRENTRY)RTMemTmpAlloc(cbNeeded);
+ if (pDirEntry)
+ {
+ rc = RTDirRead(hDir, pDirEntry, &cbNeeded);
+ RTMemTmpFree(pDirEntry);
+ }
+ return rc;
+}
+
+
+/**
+ * Adds a result.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param pGlob The glob instance data.
+ * @param cchPath The number of bytes to add from pGlob->szPath.
+ * @param uType The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAddResult(PRTPATHGLOB pGlob, size_t cchPath, uint8_t uType)
+{
+ if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+ {
+ PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + 1]));
+ if (pEntry)
+ {
+ pEntry->uType = uType;
+ pEntry->cchPath = (uint16_t)cchPath;
+ memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+ pEntry->szPath[cchPath] = '\0';
+
+ pEntry->pNext = NULL;
+ *pGlob->ppNext = pEntry;
+ pGlob->ppNext = &pEntry->pNext;
+ pGlob->cResults++;
+
+ if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+ return VINF_SUCCESS;
+ return VINF_CALLBACK_RETURN;
+ }
+ return VERR_NO_MEMORY;
+ }
+ return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Adds a result, constructing the path from two string.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param pGlob The glob instance data.
+ * @param cchPath The number of bytes to add from pGlob->szPath.
+ * @param pchName The string (usual filename) to append to the szPath.
+ * @param cchName The length of the string to append.
+ * @param uType The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAddResult2(PRTPATHGLOB pGlob, size_t cchPath, const char *pchName, size_t cchName,
+ uint8_t uType)
+{
+ if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+ {
+ PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + cchName + 1]));
+ if (pEntry)
+ {
+ pEntry->uType = uType;
+ pEntry->cchPath = (uint16_t)(cchPath + cchName);
+ memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+ memcpy(&pEntry->szPath[cchPath], pchName, cchName);
+ pEntry->szPath[cchPath + cchName] = '\0';
+
+ pEntry->pNext = NULL;
+ *pGlob->ppNext = pEntry;
+ pGlob->ppNext = &pEntry->pNext;
+ pGlob->cResults++;
+
+ if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+ return VINF_SUCCESS;
+ return VINF_CALLBACK_RETURN;
+ }
+ return VERR_NO_MEMORY;
+ }
+ return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Prepares a result, constructing the path from two string.
+ *
+ * The caller must call either rtPathGlobCommitResult or
+ * rtPathGlobRollbackResult to complete the operation.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param pGlob The glob instance data.
+ * @param cchPath The number of bytes to add from pGlob->szPath.
+ * @param pchName The string (usual filename) to append to the szPath.
+ * @param cchName The length of the string to append.
+ * @param uType The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAlmostAddResult(PRTPATHGLOB pGlob, size_t cchPath, const char *pchName, size_t cchName,
+ uint8_t uType)
+{
+ if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+ {
+ PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + cchName + 1]));
+ if (pEntry)
+ {
+ pEntry->uType = uType;
+ pEntry->cchPath = (uint16_t)(cchPath + cchName);
+ memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+ memcpy(&pEntry->szPath[cchPath], pchName, cchName);
+ pEntry->szPath[cchPath + cchName] = '\0';
+
+ pEntry->pNext = NULL;
+ *pGlob->ppNext = pEntry;
+ /* Note! We don't update ppNext here, that is done in rtPathGlobCommitResult. */
+
+ if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+ return VINF_SUCCESS;
+ return VINF_CALLBACK_RETURN;
+ }
+ return VERR_NO_MEMORY;
+ }
+ return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Commits a pending result from rtPathGlobAlmostAddResult.
+ *
+ * @param pGlob The glob instance data.
+ * @param uType The RTDIRENTRYTYPE value.
+ */
+static void rtPathGlobCommitResult(PRTPATHGLOB pGlob, uint8_t uType)
+{
+ PRTPATHGLOBENTRY pEntry = *pGlob->ppNext;
+ AssertPtr(pEntry);
+ pEntry->uType = uType;
+ pGlob->ppNext = &pEntry->pNext;
+ pGlob->cResults++;
+}
+
+
+/**
+ * Rolls back a pending result from rtPathGlobAlmostAddResult.
+ *
+ * @param pGlob The glob instance data.
+ */
+static void rtPathGlobRollbackResult(PRTPATHGLOB pGlob)
+{
+ PRTPATHGLOBENTRY pEntry = *pGlob->ppNext;
+ AssertPtr(pEntry);
+ RTMemFree(pEntry);
+ *pGlob->ppNext = NULL;
+}
+
+
+
+/**
+ * Whether to call rtPathGlobExecRecursiveVarExp for the next component.
+ *
+ * @returns true / false.
+ * @param pGlob The glob instance data.
+ * @param offPath The next path offset/length.
+ * @param iComp The next component.
+ */
+DECLINLINE(bool) rtPathGlobExecIsExpVar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+ return pGlob->aComps[iComp].fExpVariable
+ && ( !(pGlob->fFlags & RTPATHGLOB_F_IGNORE_CASE)
+ || (offPath ? !RTFsIsCaseSensitive(pGlob->szPath) : !RTFsIsCaseSensitive(".")) );
+}
+
+/**
+ * Whether to call rtPathGlobExecRecursivePlainText for the next component.
+ *
+ * @returns true / false.
+ * @param pGlob The glob instance data.
+ * @param offPath The next path offset/length.
+ * @param iComp The next component.
+ */
+DECLINLINE(bool) rtPathGlobExecIsPlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+ return pGlob->aComps[iComp].fPlain
+ && ( !(pGlob->fFlags & RTPATHGLOB_F_IGNORE_CASE)
+ || (offPath ? !RTFsIsCaseSensitive(pGlob->szPath) : !RTFsIsCaseSensitive(".")) );
+}
+
+
+/**
+ * Helper for rtPathGlobExecRecursiveVarExp and rtPathGlobExecRecursivePlainText
+ * that compares a file mode mask with dir/no-dir wishes of the caller.
+ *
+ * @returns true if match, false if not.
+ * @param pGlob The glob instance data.
+ * @param fMode The file mode (only the type is used).
+ */
+DECLINLINE(bool) rtPathGlobExecIsMatchFinalWithFileMode(PRTPATHGLOB pGlob, RTFMODE fMode)
+{
+ if (!(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)))
+ return true;
+ return RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS) == RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode);
+}
+
+
+/**
+ * Recursive globbing - star-star mode.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param pGlob The glob instance data.
+ * @param offPath The current path offset/length.
+ * @param iComp The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveStarStar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iStarStarComp,
+ size_t offStarStarPath)
+{
+ /** @todo implement multi subdir matching. */
+ return VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED;
+}
+
+
+
+/**
+ * Recursive globbing - variable expansion optimization.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param pGlob The glob instance data.
+ * @param offPath The current path offset/length.
+ * @param iComp The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveVarExp(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+ Assert(iComp < pGlob->pParsed->cComps);
+ Assert(pGlob->szPath[offPath] == '\0');
+ Assert(pGlob->aComps[iComp].fExpVariable);
+ Assert(!pGlob->aComps[iComp].fPlain);
+ Assert(!pGlob->aComps[iComp].fStarStar);
+ Assert(rtPathGlobExecIsExpVar(pGlob, offPath, iComp));
+
+ /*
+ * Fish the variable index out of the first matching instruction.
+ */
+ Assert( pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+ == RTPATHMATCHOP_VARIABLE_VALUE_CMP
+ || pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+ == RTPATHMATCHOP_VARIABLE_VALUE_ICMP);
+ uint16_t const iVar = pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].uOp2;
+
+ /*
+ * Enumerate all the variable, giving them the plain text treatment.
+ */
+ for (uint32_t iItem = 0; iItem < RTPATHMATCH_MAX_VAR_ITEMS; iItem++)
+ {
+ size_t cch;
+ int rcVar = g_aVariables[iVar].pfnQuery(iItem, &pGlob->szPath[offPath], sizeof(pGlob->szPath) - offPath, &cch,
+ &pGlob->MatchCache);
+ if (RT_SUCCESS(rcVar))
+ {
+ Assert(pGlob->szPath[offPath + cch] == '\0');
+
+ int rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if (RT_SUCCESS(rc))
+ {
+ if (pGlob->aComps[iComp].fFinal)
+ {
+ if (rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+ {
+ rc = rtPathGlobAddResult(pGlob, cch,
+ (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+ >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+ }
+ else if (RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode))
+ {
+ Assert(pGlob->aComps[iComp].fDir);
+ cch = RTPathEnsureTrailingSeparator(pGlob->szPath, sizeof(pGlob->szPath));
+ if (cch > 0)
+ {
+ if (rtPathGlobExecIsExpVar(pGlob, cch, iComp + 1))
+ rc = rtPathGlobExecRecursiveVarExp(pGlob, cch, iComp + 1);
+ else if (rtPathGlobExecIsPlainText(pGlob, cch, iComp + 1))
+ rc = rtPathGlobExecRecursivePlainText(pGlob, cch, iComp + 1);
+ else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+ rc = rtPathGlobExecRecursiveStarStar(pGlob, cch, iComp + 1, cch);
+ else
+ rc = rtPathGlobExecRecursiveGeneric(pGlob, cch, iComp + 1);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+ else
+ pGlob->cPathOverflows++;
+ }
+ }
+ /* else: file doesn't exist or something else is wrong, ignore this. */
+ if (rcVar == VINF_EOF)
+ return VINF_SUCCESS;
+ }
+ else if (rcVar == VERR_EOF)
+ return VINF_SUCCESS;
+ else if (rcVar != VERR_TRY_AGAIN)
+ {
+ Assert(rcVar == VERR_BUFFER_OVERFLOW);
+ pGlob->cPathOverflows++;
+ }
+ }
+ AssertFailedReturn(VINF_SUCCESS); /* Too many items returned, probably buggy query method. */
+}
+
+
+/**
+ * Recursive globbing - plain text optimization.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param pGlob The glob instance data.
+ * @param offPath The current path offset/length.
+ * @param iComp The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursivePlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+ /*
+ * Instead of recursing, we loop thru adjacent plain text components.
+ */
+ for (;;)
+ {
+ /*
+ * Preconditions.
+ */
+ Assert(iComp < pGlob->pParsed->cComps);
+ Assert(pGlob->szPath[offPath] == '\0');
+ Assert(pGlob->aComps[iComp].fPlain);
+ Assert(!pGlob->aComps[iComp].fExpVariable);
+ Assert(!pGlob->aComps[iComp].fStarStar);
+ Assert(rtPathGlobExecIsPlainText(pGlob, offPath, iComp));
+ Assert(pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+ == RTPATHMATCHOP_STRCMP
+ || pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+ == RTPATHMATCHOP_STRICMP);
+
+ /*
+ * Add the plain text component to the path.
+ */
+ size_t const cch = pGlob->pParsed->aComps[iComp].cch;
+ if (cch + pGlob->aComps[iComp].fDir < sizeof(pGlob->szPath) - offPath)
+ {
+ memcpy(&pGlob->szPath[offPath], &pGlob->pszPattern[pGlob->pParsed->aComps[iComp].off], cch);
+ offPath += cch;
+ pGlob->szPath[offPath] = '\0';
+
+ /*
+ * Check if it exists.
+ */
+ int rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if (RT_SUCCESS(rc))
+ {
+ if (pGlob->aComps[iComp].fFinal)
+ {
+ if (rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+ return rtPathGlobAddResult(pGlob, offPath,
+ (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+ >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+ break;
+ }
+
+ if (RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode))
+ {
+ Assert(pGlob->aComps[iComp].fDir);
+ pGlob->szPath[offPath++] = RTPATH_SLASH;
+ pGlob->szPath[offPath] = '\0';
+
+ iComp++;
+ if (rtPathGlobExecIsExpVar(pGlob, offPath, iComp))
+ return rtPathGlobExecRecursiveVarExp(pGlob, offPath, iComp);
+ if (!rtPathGlobExecIsPlainText(pGlob, offPath, iComp))
+ return rtPathGlobExecRecursiveGeneric(pGlob, offPath, iComp);
+ if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+ return rtPathGlobExecRecursiveStarStar(pGlob, offPath, iComp, offPath);
+
+ /* Continue with the next plain text component. */
+ continue;
+ }
+ }
+ /* else: file doesn't exist or something else is wrong, ignore this. */
+ }
+ else
+ pGlob->cPathOverflows++;
+ break;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Recursive globbing - generic.
+ *
+ * @returns IPRT status code.
+ * @retval VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param pGlob The glob instance data.
+ * @param offPath The current path offset/length.
+ * @param iComp The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveGeneric(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+ /*
+ * Enumerate entire directory and match each entry.
+ */
+ PRTDIR hDir;
+ int rc = RTDirOpen(&hDir, offPath ? pGlob->szPath : ".");
+ if (RT_SUCCESS(rc))
+ {
+ for (;;)
+ {
+ size_t cch = sizeof(pGlob->u);
+ rc = RTDirRead(hDir, &pGlob->u.DirEntry, &cch);
+ if (RT_SUCCESS(rc))
+ {
+ if (pGlob->aComps[iComp].fFinal)
+ {
+ /*
+ * Final component: Check if it matches the current pattern.
+ */
+ if ( !(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS))
+ || RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS)
+ == (pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY)
+ || pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
+ {
+ rc = rtPathMatchExec(pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+ &pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg],
+ &pGlob->MatchCache);
+ if (RT_SUCCESS(rc))
+ {
+ /* Construct the result. */
+ if ( pGlob->u.DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
+ || !(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)) )
+ rc = rtPathGlobAddResult2(pGlob, offPath, pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+ (uint8_t)pGlob->u.DirEntry.enmType);
+ else
+ {
+ rc = rtPathGlobAlmostAddResult(pGlob, offPath,
+ pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+ (uint8_t)RTDIRENTRYTYPE_UNKNOWN);
+ if (RT_SUCCESS(rc))
+ {
+ RTDirQueryUnknownType((*pGlob->ppNext)->szPath, false /*fFollowSymlinks*/,
+ &pGlob->u.DirEntry.enmType);
+ if ( RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS)
+ == (pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY))
+ rtPathGlobCommitResult(pGlob, (uint8_t)pGlob->u.DirEntry.enmType);
+ else
+ rtPathGlobRollbackResult(pGlob);
+ }
+ }
+ if (rc != VINF_SUCCESS)
+ break;
+ }
+ else
+ {
+ AssertMsgBreak(rc == VERR_MISMATCH, ("%Rrc\n", rc));
+ rc = VINF_SUCCESS;
+ }
+ }
+ }
+ /*
+ * Intermediate component: Directories only.
+ */
+ else if ( pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY
+ || pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
+ {
+ rc = rtPathMatchExec(pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+ &pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg],
+ &pGlob->MatchCache);
+ if (RT_SUCCESS(rc))
+ {
+ /* Recurse down into the alleged directory. */
+ cch = offPath + pGlob->u.DirEntry.cbName;
+ if (cch + 1 < sizeof(pGlob->szPath))
+ {
+ memcpy(&pGlob->szPath[offPath], pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName);
+ pGlob->szPath[cch++] = RTPATH_SLASH;
+ pGlob->szPath[cch] = '\0';
+
+ if (rtPathGlobExecIsExpVar(pGlob, cch, iComp + 1))
+ rc = rtPathGlobExecRecursiveVarExp(pGlob, cch, iComp + 1);
+ else if (rtPathGlobExecIsPlainText(pGlob, cch, iComp + 1))
+ rc = rtPathGlobExecRecursivePlainText(pGlob, cch, iComp + 1);
+ else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+ rc = rtPathGlobExecRecursiveStarStar(pGlob, cch, iComp + 1, cch);
+ else
+ rc = rtPathGlobExecRecursiveGeneric(pGlob, cch, iComp + 1);
+ if (rc != VINF_SUCCESS)
+ return rc;
+ }
+ else
+ pGlob->cPathOverflows++;
+ }
+ else
+ {
+ AssertMsgBreak(rc == VERR_MISMATCH, ("%Rrc\n", rc));
+ rc = VINF_SUCCESS;
+ }
+ }
+ }
+ /*
+ * RTDirRead failure.
+ */
+ else
+ {
+ /* The end? */
+ if (rc == VERR_NO_MORE_FILES)
+ rc = VINF_SUCCESS;
+ /* Try skip the entry if we end up with an overflow (szPath can't hold it either then). */
+ else if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ pGlob->cPathOverflows++;
+ rc = rtPathGlobSkipDirEntry(hDir, cch);
+ if (RT_SUCCESS(rc))
+ continue;
+ }
+ /* else: Any other error is unexpected and should be reported. */
+ break;
+ }
+ }
+
+ RTDirClose(hDir);
+ }
+ /* Directory doesn't exist or something else is wrong, ignore this. */
+ else
+ rc = VINF_SUCCESS;
+ return rc;
+}
+
+
+/**
+ * Executes a glob search.
+ *
+ * @returns IPRT status code.
+ * @param pGlob The glob instance data.
+ */
+static int rtPathGlobExec(PRTPATHGLOB pGlob)
+{
+ Assert(pGlob->offFirstPath < sizeof(pGlob->szPath));
+ Assert(pGlob->szPath[pGlob->offFirstPath] == '\0');
+
+ int rc;
+ if (RT_LIKELY(pGlob->iFirstComp < pGlob->pParsed->cComps))
+ {
+ /*
+ * Call the appropriate function.
+ */
+ if (rtPathGlobExecIsExpVar(pGlob, pGlob->offFirstPath, pGlob->iFirstComp))
+ rc = rtPathGlobExecRecursiveVarExp(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+ else if (rtPathGlobExecIsPlainText(pGlob, pGlob->offFirstPath, pGlob->iFirstComp))
+ rc = rtPathGlobExecRecursivePlainText(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+ else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+ rc = rtPathGlobExecRecursiveStarStar(pGlob, pGlob->offFirstPath, pGlob->iFirstComp, pGlob->offFirstPath);
+ else
+ rc = rtPathGlobExecRecursiveGeneric(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+ }
+ else
+ {
+ /*
+ * Special case where we only have a root component or tilde expansion.
+ */
+ Assert(pGlob->offFirstPath > 0);
+ rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+ if ( RT_SUCCESS(rc)
+ && rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+ rc = rtPathGlobAddResult(pGlob, pGlob->offFirstPath,
+ (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK) >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+ else
+ rc = VINF_SUCCESS;
+ }
+
+ /*
+ * Adjust the status code. Check for results, hide RTPATHGLOB_F_FIRST_ONLY
+ * status code, and add warning if necessary.
+ */
+ if (pGlob->cResults > 0)
+ {
+ if (rc == VINF_CALLBACK_RETURN)
+ rc = VINF_SUCCESS;
+ if (rc == VINF_SUCCESS)
+ {
+ if (pGlob->cPathOverflows > 0)
+ rc = VINF_BUFFER_OVERFLOW;
+ }
+ }
+ else
+ rc = VERR_FILE_NOT_FOUND;
+
+ return rc;
+}
+
+
+RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(ppHead, VERR_INVALID_POINTER);
+ *ppHead = NULL;
+ if (pcResults)
+ {
+ AssertPtrReturn(pcResults, VERR_INVALID_POINTER);
+ *pcResults = 0;
+ }
+ AssertPtrReturn(pszPattern, VERR_INVALID_POINTER);
+ AssertReturn(!(fFlags & ~RTPATHGLOB_F_MASK), VERR_INVALID_FLAGS);
+ AssertReturn((fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)) != (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS),
+ VERR_INVALID_FLAGS);
+
+ /*
+ * Parse the path.
+ */
+ size_t cbParsed = RT_OFFSETOF(RTPATHPARSED, aComps[1]); /** @todo 16 after testing */
+ PRTPATHPARSED pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
+ AssertReturn(pParsed, VERR_NO_MEMORY);
+ int rc = RTPathParse(pszPattern, pParsed, cbParsed, RTPATH_STR_F_STYLE_HOST);
+ if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ cbParsed = RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps + 1]);
+ RTMemTmpFree(pParsed);
+ pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
+ AssertReturn(pParsed, VERR_NO_MEMORY);
+
+ rc = RTPathParse(pszPattern, pParsed, cbParsed, RTPATH_STR_F_STYLE_HOST);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Check dir slash vs. only/not dir flag.
+ */
+ if ( !(fFlags & RTPATHGLOB_F_NO_DIRS)
+ || ( !(pParsed->fProps & RTPATH_PROP_DIR_SLASH)
+ && ( !(pParsed->fProps & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_UNC))
+ || pParsed->cComps > 1) ) )
+ {
+ if (pParsed->fProps & RTPATH_PROP_DIR_SLASH)
+ fFlags |= RTPATHGLOB_F_ONLY_DIRS;
+
+ /*
+ * Allocate and initialize the glob state data structure.
+ */
+ size_t cbGlob = RT_OFFSETOF(RTPATHGLOB, aComps[pParsed->cComps + 1]);
+ PRTPATHGLOB pGlob = (PRTPATHGLOB)RTMemTmpAllocZ(cbGlob);
+ if (pGlob)
+ {
+ pGlob->pszPattern = pszPattern;
+ pGlob->fFlags = fFlags;
+ pGlob->pParsed = pParsed;
+ pGlob->ppNext = &pGlob->pHead;
+ rc = rtPathGlobParse(pGlob, pszPattern, pParsed, fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Execute the search.
+ */
+ rc = rtPathGlobExec(pGlob);
+ if (RT_SUCCESS(rc))
+ {
+ *ppHead = pGlob->pHead;
+ if (pcResults)
+ *pcResults = pGlob->cResults;
+ }
+ else
+ RTPathGlobFree(pGlob->pHead);
+ }
+
+ RTMemTmpFree(pGlob->MatchInstrAlloc.paInstructions);
+ RTMemTmpFree(pGlob);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+ RTMemTmpFree(pParsed);
+ return rc;
+
+
+}
+
+
+RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead)
+{
+ PRTPATHGLOBENTRY pCur = (PRTPATHGLOBENTRY)pHead;
+ while (pCur)
+ {
+ PRTPATHGLOBENTRY pNext = pCur->pNext;
+ pCur->pNext = NULL;
+ RTMemFree(pCur);
+ pCur = pNext;
+ }
+}
+
diff --git a/src/VBox/Runtime/common/string/memrchr.asm b/src/VBox/Runtime/common/string/memrchr.asm
new file mode 100644
index 0000000..dbebb94
--- /dev/null
+++ b/src/VBox/Runtime/common/string/memrchr.asm
@@ -0,0 +1,90 @@
+; $Id: memrchr.asm $
+;; @file
+; IPRT - No-CRT memrchr - AMD64 & X86.
+;
+
+;
+; Copyright (C) 2006-2015 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+; VirtualBox OSE distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+
+%include "iprt/asmdefs.mac"
+
+BEGINCODE
+
+;;
+; @param pv gcc: rdi msc: ecx x86:[esp+4]
+; @param ch gcc: esi msc: edx x86:[esp+8]
+; @param cb gcc: rdx msc: r8 x86:[esp+0ch]
+RT_NOCRT_BEGINPROC memrchr
+ std
+%ifdef RT_ARCH_AMD64
+ %ifdef ASM_CALL64_MSC
+ or r8, r8
+ jz .not_found_early
+
+ mov r9, rdi ; save rdi
+ mov eax, edx
+ lea rdi, [rcx + r8 - 1]
+ mov rcx, r8
+ %else
+ mov rcx, rdx
+ jrcxz .not_found_early
+
+ mov eax, esi
+ lea rdi, [rdi + rcx - 1]
+ %endif
+
+%else
+ mov ecx, [esp + 0ch]
+ jecxz .not_found_early
+ mov edx, edi ; save edi
+ mov eax, [esp + 8]
+ mov edi, [esp + 4]
+ lea edi, [edi + ecx - 1]
+%endif
+
+ ; do the search
+ repne scasb
+ jne .not_found
+
+ ; found it
+ lea xAX, [xDI + 1]
+%ifdef ASM_CALL64_MSC
+ mov rdi, r9
+%endif
+%ifdef RT_ARCH_X86
+ mov edi, edx
+%endif
+ cld
+ ret
+
+.not_found:
+%ifdef ASM_CALL64_MSC
+ mov rdi, r9
+%endif
+%ifdef RT_ARCH_X86
+ mov edi, edx
+%endif
+.not_found_early:
+ xor eax, eax
+ cld
+ ret
+ENDPROC RT_NOCRT(memrchr)
+
diff --git a/src/VBox/Runtime/common/vfs/vfsstdfile.cpp b/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
index 5f023e7..71f3b54 100644
--- a/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
+++ b/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
@@ -488,7 +488,10 @@ RTDECL(int) RTVfsIoStrmFromRTFile(RTFILE hFile, uint64_t fOpen, bool fLeaveOpen,
RTVFSFILE hVfsFile;
int rc = RTVfsFileFromRTFile(hFile, fOpen, fLeaveOpen, &hVfsFile);
if (RT_SUCCESS(rc))
+ {
*phVfsIos = RTVfsFileToIoStream(hVfsFile);
+ RTVfsFileRelease(hVfsFile);
+ }
return rc;
}
diff --git a/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp b/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp
new file mode 100644
index 0000000..c65e1a4
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp
@@ -0,0 +1,148 @@
+/* $Id: RTCrStoreCreateSnapshotById-generic.cpp $ */
+/** @file
+ * IPRT - Generic RTCrStoreCreateSnapshotById implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crypto/store.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/dir.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** Unix root prefix. */
+#ifdef RT_OS_OS2
+# define UNIX_ROOT "/@unixroot@"
+#elif defined(RT_OS_WINDOWS)
+# define UNIX_ROOT "C:/cygwin"
+#else
+# define UNIX_ROOT
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** System PEM files worth looking at.
+ * @remarks Several of these could be symlinks to one of the others.
+ */
+static const char *g_apszSystemPemFiles[] =
+{
+ UNIX_ROOT "/etc/ssl/certs/ca-certificates.crt",
+ UNIX_ROOT "/etc/ssl/cert.pem",
+ UNIX_ROOT "/etc/ca-certificates/extracted/tls-ca-bundle.pem", /* Arch linux (ca 2015-08-xx) */
+ UNIX_ROOT "/etc/ca-certificates/extracted/email-ca-bundle.pem",
+ UNIX_ROOT "/etc/ca-certificates/extracted/objsign-ca-bundle.pem",
+ UNIX_ROOT "/etc/ca-certificates/extracted/ca-bundle.trust.crt",
+ UNIX_ROOT "/etc/ca-certificates/extracted/ca-bundle.trust.crt",
+ UNIX_ROOT "/etc/pki/tls/certs/ca-bundle.crt", /* Oracle Linux 5 */
+ UNIX_ROOT "/etc/pki/tls/cert.pem",
+ UNIX_ROOT "/etc/certs/ca-certificates.crt", /* Solaris 11 */
+ UNIX_ROOT "/etc/curl/curlCA",
+};
+
+/**
+ * System directories containing lots of pem/crt files.
+ */
+static const char *g_apszSystemPemDirs[] =
+{
+ UNIX_ROOT "/etc/openssl/certs/",
+ UNIX_ROOT "/etc/ssl/certs/",
+ UNIX_ROOT "/etc/ca-certificates/extracted/cadir/",
+ UNIX_ROOT "/etc/certs/CA/", /* Solaris 11 */
+};
+
+
+RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo)
+{
+ AssertReturn(enmStoreId > RTCRSTOREID_INVALID && enmStoreId < RTCRSTOREID_END, VERR_INVALID_PARAMETER);
+
+ /*
+ * Create an empty in-memory store.
+ */
+ RTCRSTORE hStore;
+ uint32_t cExpected = enmStoreId == RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES ? 256 : 0;
+ int rc = RTCrStoreCreateInMem(&hStore, cExpected);
+ if (RT_SUCCESS(rc))
+ {
+ *phStore = hStore;
+
+ /*
+ * Add system certificates if part of the given store ID.
+ */
+ bool fFound = false;
+ rc = VINF_SUCCESS;
+ if (enmStoreId == RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES)
+ {
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_apszSystemPemFiles); i++)
+ if (RTFileExists(g_apszSystemPemFiles[i]))
+ {
+ fFound = true;
+ int rc2 = RTCrStoreCertAddFromFile(hStore,
+ RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ g_apszSystemPemFiles[i], pErrInfo);
+ if (RT_FAILURE(rc2))
+ rc = -rc2;
+ }
+
+ /*
+ * If we didn't find any of the certificate collection files, go hunting
+ * for directories containing PEM/CRT files with single certificates.
+ */
+ if (!fFound)
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_apszSystemPemDirs); i++)
+ if (RTDirExists(g_apszSystemPemDirs[i]))
+ {
+ static RTSTRTUPLE const s_aSuffixes[] =
+ {
+ { RT_STR_TUPLE(".crt") },
+ { RT_STR_TUPLE(".pem") },
+ { RT_STR_TUPLE(".PEM") },
+ { RT_STR_TUPLE(".CRT") },
+ };
+ fFound = true;
+ int rc2 = RTCrStoreCertAddFromDir(hStore,
+ RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ g_apszSystemPemDirs[i], &s_aSuffixes[0], RT_ELEMENTS(s_aSuffixes),
+ pErrInfo);
+ if (RT_FAILURE(rc2))
+ rc = -rc2;
+ }
+ }
+ }
+ else
+ RTErrInfoAdd(pErrInfo, rc, " RTCrStoreCreateInMem failed");
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCreateSnapshotById);
+
diff --git a/src/VBox/Runtime/generic/RTMpOnPair-generic.cpp b/src/VBox/Runtime/generic/RTMpOnPair-generic.cpp
new file mode 100644
index 0000000..315dff4
--- /dev/null
+++ b/src/VBox/Runtime/generic/RTMpOnPair-generic.cpp
@@ -0,0 +1,137 @@
+/* $Id: RTMpOnPair-generic.cpp $ */
+/** @file
+ * IPRT - RTMpOnPair, generic implementation using RTMpOnAll.
+ */
+
+/*
+ * Copyright (C) 2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/mp.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * Argument package for the generic RTMpOnPair implemenetation.
+ */
+typedef struct RTMPONPAIRGENERIC
+{
+ RTCPUID idCpu1;
+ RTCPUID idCpu2;
+ PFNRTMPWORKER pfnWorker;
+ void *pvUser1;
+ void *pvUser2;
+ /** Count of how many CPUs actually showed up. */
+ uint32_t volatile cPresent;
+} RTMPONPAIRGENERIC;
+/** Pointer to the an argument package for the generic RTMpOnPair
+ * implemenation. */
+typedef RTMPONPAIRGENERIC *PRTMPONPAIRGENERIC;
+
+
+/**
+ * @callback_method_impl{FNRTMPWORKER,
+ * Used by RTMpOnPair to call the worker on the two specified CPUs.}
+ */
+static DECLCALLBACK(void) rtMpOnPairGenericWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PRTMPONPAIRGENERIC pArgs = (PRTMPONPAIRGENERIC)pvUser1;
+
+ /*
+ * Only the two choosen CPUs should call the worker function, count how
+ * many of them that showed up.
+ */
+ if ( idCpu == pArgs->idCpu1
+ || idCpu == pArgs->idCpu2)
+ {
+ ASMAtomicIncU32(&pArgs->cPresent);
+ pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ }
+}
+
+#if 0 /* Missing RTMpOnAllIsConcurrentSafe on 4.3. Was introduced in r95899 but that is a huge changeset that we don't want to backport. Right now I only need VERR_WRONG_TYPE... */
+RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ int rc;
+ AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER);
+ AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS);
+ if ((fFlags & RTMPON_F_CONCURRENT_EXEC) && !RTMpOnAllIsConcurrentSafe())
+ return VERR_NOT_SUPPORTED;
+
+ /*
+ * Check that both CPUs are online before doing the broadcast call.
+ */
+ if ( RTMpIsCpuOnline(idCpu1)
+ && RTMpIsCpuOnline(idCpu2))
+ {
+ RTMPONPAIRGENERIC Args;
+ Args.idCpu1 = idCpu1;
+ Args.idCpu2 = idCpu2;
+ Args.pfnWorker = pfnWorker;
+ Args.pvUser1 = pvUser1;
+ Args.pvUser2 = pvUser2;
+ Args.cPresent = 0;
+ rc = RTMpOnAll(rtMpOnPairGenericWorker, &Args, pvUser2);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Let's see if both of the CPUs showed up.
+ */
+ if (RT_LIKELY(Args.cPresent == 2))
+ { /* likely */ }
+ else if (Args.cPresent == 0)
+ rc = VERR_CPU_OFFLINE;
+ else if (Args.cPresent == 1)
+ rc = VERR_NOT_ALL_CPUS_SHOWED;
+ else
+ {
+ rc = VERR_CPU_IPE_1;
+ AssertMsgFailed(("cPresent=%#x\n", Args.cPresent));
+ }
+ }
+ }
+ /*
+ * A CPU must be present to be considered just offline.
+ */
+ else if ( RTMpIsCpuPresent(idCpu1)
+ && RTMpIsCpuPresent(idCpu2))
+ rc = VERR_CPU_OFFLINE;
+ else
+ rc = VERR_CPU_NOT_FOUND;
+ return rc;
+}
+
+RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void)
+{
+ return RTMpOnAllIsConcurrentSafe();
+}
+#endif
+
diff --git a/src/VBox/Runtime/generic/createtemp-generic.cpp b/src/VBox/Runtime/generic/createtemp-generic.cpp
index addbb5d..6e923dd 100644
--- a/src/VBox/Runtime/generic/createtemp-generic.cpp
+++ b/src/VBox/Runtime/generic/createtemp-generic.cpp
@@ -234,3 +234,49 @@ RTDECL(int) RTFileCreateTempSecure(char *pszTemplate)
}
}
RT_EXPORT_SYMBOL(RTFileCreateTempSecure);
+
+
+RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen)
+{
+ AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS);
+ AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS);
+
+ /*
+ * Start by obtaining the path to the temporary directory.
+ */
+ int rc = RTPathTemp(pszFilename, cbFilename);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Add a filename pattern.
+ */
+ static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp";
+ rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate);
+ if (RT_SUCCESS(rc))
+ {
+ char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5;
+ unsigned cXes = sizeof(s_szTemplate) - 1 - 4 - 5;
+ Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.');
+
+ /*
+ * Try 10000 times with random names.
+ */
+ unsigned cTriesLeft = 10000;
+ while (cTriesLeft-- > 0)
+ {
+ rtCreateTempFillTemplate(pszX, cXes);
+ rc = RTFileOpen(phFile, pszFilename, fOpen);
+ if (RT_SUCCESS(rc))
+ return rc;
+ }
+ }
+ }
+
+ if (cbFilename)
+ *pszFilename = '\0';
+ *phFile = NIL_RTFILE;
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTFileOpenTemp);
+
+
diff --git a/src/VBox/Runtime/generic/fs-stubs-generic.cpp b/src/VBox/Runtime/generic/fs-stubs-generic.cpp
index 9f07d41..9a85029 100644
--- a/src/VBox/Runtime/generic/fs-stubs-generic.cpp
+++ b/src/VBox/Runtime/generic/fs-stubs-generic.cpp
@@ -67,7 +67,11 @@ RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial)
RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties)
{
pProperties->cbMaxComponent = 255;
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
+ pProperties->fCaseSensitive = false;
+#else
pProperties->fCaseSensitive = true;
+#endif
pProperties->fCompressed = false;
pProperties->fFileCompression = false;
pProperties->fReadOnly = false;
@@ -77,3 +81,13 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
return VINF_SUCCESS;
}
+
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
+ return false;
+#else
+ return true;
+#endif
+}
+
diff --git a/src/VBox/Runtime/generic/http-curl.cpp b/src/VBox/Runtime/generic/http-curl.cpp
new file mode 100644
index 0000000..8fd23d9
--- /dev/null
+++ b/src/VBox/Runtime/generic/http-curl.cpp
@@ -0,0 +1,2449 @@
+/* $Id: http-curl.cpp $ */
+/** @file
+ * IPRT - HTTP client API, cURL based.
+ */
+
+/*
+ * Copyright (C) 2012-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP RTLOGGROUP_HTTP
+#include <iprt/http.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/cidr.h>
+#include <iprt/crypto/store.h>
+#include <iprt/ctype.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/ldr.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+#include <iprt/net.h>
+#include <iprt/once.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+#include <iprt/uri.h>
+
+#include "internal/magics.h"
+
+#include <curl/curl.h>
+
+#ifdef RT_OS_DARWIN
+# include <CoreFoundation/CoreFoundation.h>
+# include <SystemConfiguration/SystemConfiguration.h>
+# include <CoreServices/CoreServices.h>
+#endif
+#ifdef RT_OS_WINDOWS
+# include <Winhttp.h>
+#endif
+
+#ifdef RT_OS_LINUX
+//# define IPRT_USE_LIBPROXY
+#endif
+#ifdef IPRT_USE_LIBPROXY
+# include <stdlib.h> /* free */
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Internal HTTP client instance.
+ */
+typedef struct RTHTTPINTERNAL
+{
+ /** Magic value. */
+ uint32_t u32Magic;
+ /** cURL handle. */
+ CURL *pCurl;
+ /** The last response code. */
+ long lLastResp;
+ /** Custom headers/ */
+ struct curl_slist *pHeaders;
+ /** CA certificate file for HTTPS authentication. */
+ char *pszCaFile;
+ /** Whether to delete the CA on destruction. */
+ bool fDeleteCaFile;
+
+ /** Set if we've applied a CURLOTP_USERAGENT already. */
+ bool fHaveSetUserAgent;
+ /** Set if we've got a user agent header, otherwise clear. */
+ bool fHaveUserAgentHeader;
+
+ /** @name Proxy settings.
+ * When fUseSystemProxySettings is set, the other members will be updated each
+ * time we're presented with a new URL. The members reflect the cURL
+ * configuration.
+ *
+ * @{ */
+ /** Set if we should use the system proxy settings for a URL.
+ * This means reconfiguring cURL for each request. */
+ bool fUseSystemProxySettings;
+ /** Set if we've detected no proxy necessary. */
+ bool fNoProxy;
+ /** Proxy host name (RTStrFree). */
+ char *pszProxyHost;
+ /** Proxy port number (UINT32_MAX if not specified). */
+ uint32_t uProxyPort;
+ /** The proxy type (CURLPROXY_HTTP, CURLPROXY_SOCKS5, ++). */
+ curl_proxytype enmProxyType;
+ /** Proxy username (RTStrFree). */
+ char *pszProxyUsername;
+ /** Proxy password (RTStrFree). */
+ char *pszProxyPassword;
+ /** @} */
+
+ /** Abort the current HTTP request if true. */
+ bool volatile fAbort;
+ /** Set if someone is preforming an HTTP operation. */
+ bool volatile fBusy;
+ /** The location field for 301 responses. */
+ char *pszRedirLocation;
+
+ /** Output callback data. */
+ union
+ {
+ /** For file destination. */
+ RTFILE hFile;
+ /** For memory destination. */
+ struct
+ {
+ /** The current size (sans terminator char). */
+ size_t cb;
+ /** The currently allocated size. */
+ size_t cbAllocated;
+ /** Pointer to the buffer. */
+ uint8_t *pb;
+ } Mem;
+ } Output;
+ /** Output callback status. */
+ int rcOutput;
+ /** Download size hint set by the progress callback. */
+ uint64_t cbDownloadHint;
+} RTHTTPINTERNAL;
+/** Pointer to an internal HTTP client instance. */
+typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
+
+
+#ifdef RT_OS_WINDOWS
+/** @name Windows: Types for dynamically resolved APIs
+ * @{ */
+typedef HINTERNET (WINAPI * PFNWINHTTPOPEN)(LPCWSTR, DWORD, LPCWSTR, LPCWSTR, DWORD);
+typedef BOOL (WINAPI * PFNWINHTTPCLOSEHANDLE)(HINTERNET);
+typedef BOOL (WINAPI * PFNWINHTTPGETPROXYFORURL)(HINTERNET, LPCWSTR, WINHTTP_AUTOPROXY_OPTIONS *, WINHTTP_PROXY_INFO *);
+typedef BOOL (WINAPI * PFNWINHTTPGETDEFAULTPROXYCONFIGURATION)(WINHTTP_PROXY_INFO *);
+typedef BOOL (WINAPI * PFNWINHTTPGETIEPROXYCONFIGFORCURRENTUSER)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *);
+/** @} */
+#endif
+
+#ifdef IPRT_USE_LIBPROXY
+typedef struct px_proxy_factory *PLIBPROXYFACTORY;
+typedef PLIBPROXYFACTORY (* PFNLIBPROXYFACTORYCTOR)(void);
+typedef void (* PFNLIBPROXYFACTORYDTOR)(PLIBPROXYFACTORY);
+typedef char ** (* PFNLIBPROXYFACTORYGETPROXIES)(PLIBPROXYFACTORY, const char *);
+#endif
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @def RTHTTP_MAX_MEM_DOWNLOAD
+ * The max size we are allowed to download to a memory buffer.
+ *
+ * @remarks The minus 1 is for the trailing zero terminator we always add.
+ */
+#if ARCH_BITS == 64
+# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE (UINT32_C(64)*_1M - 1)
+#else
+# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE (UINT32_C(32)*_1M - 1)
+#endif
+
+/** Checks whether a cURL return code indicates success. */
+#define CURL_SUCCESS(rcCurl) RT_LIKELY(rcCurl == CURLE_OK)
+/** Checks whether a cURL return code indicates failure. */
+#define CURL_FAILURE(rcCurl) RT_UNLIKELY(rcCurl != CURLE_OK)
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
+ do { \
+ AssertPtrReturn((hHttp), (rcCurl)); \
+ AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
+ } while (0)
+
+/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
+#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
+
+/** Validates a handle and returns (void) if not valid. */
+#define RTHTTP_VALID_RETURN_VOID(hHttp) \
+ do { \
+ AssertPtrReturnVoid(hHttp); \
+ AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
+ } while (0)
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef RT_OS_WINDOWS
+/** @name Windows: Dynamically resolved APIs
+ * @{ */
+static RTONCE g_WinResolveImportsOnce = RTONCE_INITIALIZER;
+static PFNWINHTTPOPEN g_pfnWinHttpOpen = NULL;
+static PFNWINHTTPCLOSEHANDLE g_pfnWinHttpCloseHandle = NULL;
+static PFNWINHTTPGETPROXYFORURL g_pfnWinHttpGetProxyForUrl = NULL;
+static PFNWINHTTPGETDEFAULTPROXYCONFIGURATION g_pfnWinHttpGetDefaultProxyConfiguration = NULL;
+static PFNWINHTTPGETIEPROXYCONFIGFORCURRENTUSER g_pfnWinHttpGetIEProxyConfigForCurrentUser = NULL;
+/** @} */
+#endif
+
+#ifdef IPRT_USE_LIBPROXY
+/** @name Dynamaically resolved libproxy APIs.
+ * @{ */
+static RTONCE g_LibProxyResolveImportsOnce = RTONCE_INITIALIZER;
+static RTLDRMOD g_hLdrLibProxy = NIL_RTLDRMOD;
+static PFNLIBPROXYFACTORYCTOR g_pfnLibProxyFactoryCtor = NULL;
+static PFNLIBPROXYFACTORYDTOR g_pfnLibProxyFactoryDtor = NULL;
+static PFNLIBPROXYFACTORYGETPROXIES g_pfnLibProxyFactoryGetProxies = NULL;
+/** @} */
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis);
+#ifdef RT_OS_DARWIN
+static int rtHttpDarwinTryConfigProxies(PRTHTTPINTERNAL pThis, CFArrayRef hArrayProxies, CFURLRef hUrlTarget, bool fIgnorePacType);
+#endif
+
+
+RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
+{
+ AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
+
+ /** @todo r=bird: rainy day: curl_global_init is not thread safe, only a
+ * problem if multiple threads get here at the same time. */
+ int rc = VERR_HTTP_INIT_FAILED;
+ CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
+ if (!CURL_FAILURE(rcCurl))
+ {
+ CURL *pCurl = curl_easy_init();
+ if (pCurl)
+ {
+ PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
+ if (pThis)
+ {
+ pThis->u32Magic = RTHTTP_MAGIC;
+ pThis->pCurl = pCurl;
+ pThis->fUseSystemProxySettings = true;
+
+ *phHttp = (RTHTTP)pThis;
+
+ return VINF_SUCCESS;
+ }
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ rc = VERR_HTTP_INIT_FAILED;
+ }
+ curl_global_cleanup();
+ return rc;
+}
+
+
+RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
+{
+ if (hHttp == NIL_RTHTTP)
+ return;
+
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN_VOID(pThis);
+
+ Assert(!pThis->fBusy);
+
+ pThis->u32Magic = RTHTTP_MAGIC_DEAD;
+
+ curl_easy_cleanup(pThis->pCurl);
+ pThis->pCurl = NULL;
+
+ if (pThis->pHeaders)
+ curl_slist_free_all(pThis->pHeaders);
+
+ rtHttpUnsetCaFile(pThis);
+ Assert(!pThis->pszCaFile);
+
+ if (pThis->pszRedirLocation)
+ RTStrFree(pThis->pszRedirLocation);
+
+ RTStrFree(pThis->pszProxyHost);
+ RTStrFree(pThis->pszProxyUsername);
+ if (pThis->pszProxyPassword)
+ {
+ RTMemWipeThoroughly(pThis->pszProxyPassword, strlen(pThis->pszProxyPassword), 2);
+ RTStrFree(pThis->pszProxyPassword);
+ }
+
+ RTMemFree(pThis);
+
+ curl_global_cleanup();
+}
+
+
+RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ pThis->fAbort = true;
+
+ return VINF_SUCCESS;
+}
+
+
+RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+ Assert(!pThis->fBusy);
+
+ if (!pThis->pszRedirLocation)
+ return VERR_HTTP_NOT_FOUND;
+
+ return RTStrDupEx(ppszRedirLocation, pThis->pszRedirLocation);
+}
+
+
+RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+ AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER);
+
+ /*
+ * Change the settings.
+ */
+ pThis->fUseSystemProxySettings = true;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * rtHttpConfigureProxyForUrl: Update cURL proxy settings as needed.
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP client instance.
+ * @param enmProxyType The proxy type.
+ * @param pszHost The proxy host name.
+ * @param uPort The proxy port number.
+ * @param pszUsername The proxy username, or NULL if none.
+ * @param pszPassword The proxy password, or NULL if none.
+ */
+static int rtHttpUpdateProxyConfig(PRTHTTPINTERNAL pThis, curl_proxytype enmProxyType, const char *pszHost,
+ uint32_t uPort, const char *pszUsername, const char *pszPassword)
+{
+ int rcCurl;
+ AssertReturn(pszHost, VERR_INVALID_PARAMETER);
+ Log(("rtHttpUpdateProxyConfig: pThis=%p type=%d host='%s' port=%u user='%s'%s\n",
+ pThis, enmProxyType, pszHost, uPort, pszUsername, pszPassword ? " with password" : " without password"));
+
+#ifdef CURLOPT_NOPROXY
+ if (pThis->fNoProxy)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROXY, (const char *)NULL);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_NOPROXY=NULL: %d (%#x)\n", rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ pThis->fNoProxy = false;
+ }
+#endif
+
+ if (enmProxyType != pThis->enmProxyType)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYTYPE, (long)enmProxyType);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYTYPE=%d: %d (%#x)\n", enmProxyType, rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ pThis->enmProxyType = CURLPROXY_HTTP;
+ }
+
+ if (uPort != pThis->uProxyPort)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)uPort);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYPORT=%d: %d (%#x)\n", uPort, rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ pThis->uProxyPort = uPort;
+ }
+
+ if ( pszUsername != pThis->pszProxyUsername
+ || RTStrCmp(pszUsername, pThis->pszProxyUsername))
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, pszUsername);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYUSERNAME=%s: %d (%#x)\n", pszUsername, rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ if (pThis->pszProxyUsername)
+ {
+ RTStrFree(pThis->pszProxyUsername);
+ pThis->pszProxyUsername = NULL;
+ }
+ if (pszUsername)
+ {
+ pThis->pszProxyUsername = RTStrDup(pszUsername);
+ AssertReturn(pThis->pszProxyUsername, VERR_NO_STR_MEMORY);
+ }
+ }
+
+ if ( pszPassword != pThis->pszProxyPassword
+ || RTStrCmp(pszPassword, pThis->pszProxyPassword))
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, pszPassword);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXYPASSWORD=%s: %d (%#x)\n", pszPassword ? "xxx" : NULL, rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ if (pThis->pszProxyPassword)
+ {
+ RTMemWipeThoroughly(pThis->pszProxyPassword, strlen(pThis->pszProxyPassword), 2);
+ RTStrFree(pThis->pszProxyPassword);
+ pThis->pszProxyPassword = NULL;
+ }
+ if (pszPassword)
+ {
+ pThis->pszProxyPassword = RTStrDup(pszPassword);
+ AssertReturn(pThis->pszProxyPassword, VERR_NO_STR_MEMORY);
+ }
+ }
+
+ if ( pszHost != pThis->pszProxyHost
+ || RTStrCmp(pszHost, pThis->pszProxyHost))
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, pszHost);
+ AssertMsgReturn(rcCurl == CURLE_OK, ("CURLOPT_PROXY=%s: %d (%#x)\n", pszHost, rcCurl, rcCurl),
+ VERR_HTTP_CURL_PROXY_CONFIG);
+ if (pThis->pszProxyHost)
+ {
+ RTStrFree(pThis->pszProxyHost);
+ pThis->pszProxyHost = NULL;
+ }
+ if (pszHost)
+ {
+ pThis->pszProxyHost = RTStrDup(pszHost);
+ AssertReturn(pThis->pszProxyHost, VERR_NO_STR_MEMORY);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * rtHttpConfigureProxyForUrl: Disables proxying.
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP client instance.
+ */
+static int rtHttpUpdateAutomaticProxyDisable(PRTHTTPINTERNAL pThis)
+{
+ Log(("rtHttpUpdateAutomaticProxyDisable: pThis=%p\n", pThis));
+
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTP) == CURLE_OK, VERR_INTERNAL_ERROR_2);
+ pThis->enmProxyType = CURLPROXY_HTTP;
+
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)1080) == CURLE_OK, VERR_INTERNAL_ERROR_2);
+ pThis->uProxyPort = 1080;
+
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2);
+ if (pThis->pszProxyUsername)
+ {
+ RTStrFree(pThis->pszProxyUsername);
+ pThis->pszProxyUsername = NULL;
+ }
+
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2);
+ if (pThis->pszProxyPassword)
+ {
+ RTStrFree(pThis->pszProxyPassword);
+ pThis->pszProxyPassword = NULL;
+ }
+
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, (const char *)NULL) == CURLE_OK, VERR_INTERNAL_ERROR_2);
+ if (pThis->pszProxyHost)
+ {
+ RTStrFree(pThis->pszProxyHost);
+ pThis->pszProxyHost = NULL;
+ }
+
+#ifdef CURLOPT_NOPROXY
+ /* No proxy for everything! */
+ AssertReturn(curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROXY, "*") == CURLE_OK, CURLOPT_PROXY);
+ pThis->fNoProxy = true;
+#endif
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * See if the host name of the URL is included in the stripped no_proxy list.
+ *
+ * The no_proxy list is a colon or space separated list of domain names for
+ * which there should be no proxying. Given "no_proxy=oracle.com" neither the
+ * URL "http://www.oracle.com" nor "http://oracle.com" will not be proxied, but
+ * "http://notoracle.com" will be.
+ *
+ * @returns true if the URL is in the no_proxy list, otherwise false.
+ * @param pszUrl The URL.
+ * @param pszNoProxyList The stripped no_proxy list.
+ */
+static bool rtHttpUrlInNoProxyList(const char *pszUrl, const char *pszNoProxyList)
+{
+ /*
+ * Check for just '*', diabling proxying for everything.
+ * (Caller stripped pszNoProxyList.)
+ */
+ if (*pszNoProxyList == '*' && pszNoProxyList[1] == '\0')
+ return true;
+
+ /*
+ * Empty list? (Caller stripped it, remember).
+ */
+ if (!*pszNoProxyList)
+ return false;
+
+ /*
+ * We now need to parse the URL and extract the host name.
+ */
+ RTURIPARSED Parsed;
+ int rc = RTUriParse(pszUrl, &Parsed);
+ AssertRCReturn(rc, false);
+ char *pszHost = RTUriParsedAuthorityHost(pszUrl, &Parsed);
+ if (!pszHost) /* Don't assert, in case of file:///xxx or similar blunder. */
+ return false;
+
+ bool fRet = false;
+ size_t const cchHost = strlen(pszHost);
+ if (cchHost)
+ {
+ /*
+ * The list is comma or space separated, walk it and match host names.
+ */
+ while (*pszNoProxyList != '\0')
+ {
+ /* Strip leading slashes, commas and dots. */
+ char ch;
+ while ( (ch = *pszNoProxyList) == ','
+ || ch == '.'
+ || RT_C_IS_SPACE(ch))
+ pszNoProxyList++;
+
+ /* Find the end. */
+ size_t cch = RTStrOffCharOrTerm(pszNoProxyList, ',');
+ size_t offNext = RTStrOffCharOrTerm(pszNoProxyList, ' ');
+ cch = RT_MIN(cch, offNext);
+ offNext = cch;
+
+ /* Trip trailing spaces, well tabs and stuff. */
+ while (cch > 0 && RT_C_IS_SPACE(pszNoProxyList[cch - 1]))
+ cch--;
+
+ /* Do the matching, if we have anything to work with. */
+ if (cch > 0)
+ {
+ if ( ( cch == cchHost
+ && RTStrNICmp(pszNoProxyList, pszHost, cch) == 0)
+ || ( cch < cchHost
+ && pszHost[cchHost - cch - 1] == '.'
+ && RTStrNICmp(pszNoProxyList, &pszHost[cchHost - cch], cch) == 0) )
+ {
+ fRet = true;
+ break;
+ }
+ }
+
+ /* Next. */
+ pszNoProxyList += offNext;
+ }
+ }
+
+ RTStrFree(pszHost);
+ return fRet;
+}
+
+
+/**
+ * Configures a proxy given a "URL" like specification.
+ *
+ * Format is [<scheme>"://"][<userid>[@<password>]:]<server>[":"<port>].
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP client instance.
+ * @param pszProxyUrl The proxy server "URL".
+ */
+static int rtHttpConfigureProxyFromUrl(PRTHTTPINTERNAL pThis, const char *pszProxyUrl)
+{
+ /*
+ * Make sure it can be parsed as an URL.
+ */
+ char *pszFreeMe = NULL;
+ if (!strstr(pszProxyUrl, "://"))
+ {
+ static const char s_szPrefix[] = "http://";
+ size_t cchProxyUrl = strlen(pszProxyUrl);
+ pszFreeMe = (char *)RTMemTmpAlloc(sizeof(s_szPrefix) + cchProxyUrl);
+ if (pszFreeMe)
+ {
+ memcpy(pszFreeMe, s_szPrefix, sizeof(s_szPrefix) - 1);
+ memcpy(&pszFreeMe[sizeof(s_szPrefix) - 1], pszProxyUrl, cchProxyUrl);
+ pszFreeMe[sizeof(s_szPrefix) - 1 + cchProxyUrl] = '\0';
+ pszProxyUrl = pszFreeMe;
+ }
+ else
+ return VERR_NO_TMP_MEMORY;
+ }
+
+ RTURIPARSED Parsed;
+ int rc = RTUriParse(pszProxyUrl, &Parsed);
+ if (RT_SUCCESS(rc))
+ {
+ bool fDone = false;
+ char *pszHost = RTUriParsedAuthorityHost(pszProxyUrl, &Parsed);
+ if (pszHost)
+ {
+ /*
+ * We've got a host name, try get the rest.
+ */
+ char *pszUsername = RTUriParsedAuthorityUsername(pszProxyUrl, &Parsed);
+ char *pszPassword = RTUriParsedAuthorityPassword(pszProxyUrl, &Parsed);
+ uint32_t uProxyPort = RTUriParsedAuthorityPort(pszProxyUrl, &Parsed);
+ curl_proxytype enmProxyType;
+ if (RTUriIsSchemeMatch(pszProxyUrl, "http"))
+ {
+ enmProxyType = CURLPROXY_HTTP;
+ if (uProxyPort == UINT32_MAX)
+ uProxyPort = 80;
+ }
+ else if ( RTUriIsSchemeMatch(pszProxyUrl, "socks4")
+ || RTUriIsSchemeMatch(pszProxyUrl, "socks"))
+ enmProxyType = CURLPROXY_SOCKS4;
+ else if (RTUriIsSchemeMatch(pszProxyUrl, "socks4a"))
+ enmProxyType = CURLPROXY_SOCKS4A;
+ else if (RTUriIsSchemeMatch(pszProxyUrl, "socks5"))
+ enmProxyType = CURLPROXY_SOCKS5;
+ else if (RTUriIsSchemeMatch(pszProxyUrl, "socks5h"))
+ enmProxyType = CURLPROXY_SOCKS5_HOSTNAME;
+ else
+ {
+ enmProxyType = CURLPROXY_HTTP;
+ if (uProxyPort == UINT32_MAX)
+ uProxyPort = 8080;
+ }
+
+ /* Guess the port from the proxy type if not given. */
+ if (uProxyPort == UINT32_MAX)
+ uProxyPort = 1080; /* CURL_DEFAULT_PROXY_PORT */
+
+ rc = rtHttpUpdateProxyConfig(pThis, enmProxyType, pszHost, uProxyPort, pszUsername, pszPassword);
+
+ RTStrFree(pszUsername);
+ RTStrFree(pszPassword);
+ RTStrFree(pszHost);
+ }
+ else
+ AssertMsgFailed(("RTUriParsedAuthorityHost('%s',) -> NULL\n", pszProxyUrl));
+ }
+ else
+ AssertMsgFailed(("RTUriParse('%s',) -> %Rrc\n", pszProxyUrl, rc));
+
+ if (pszFreeMe)
+ RTMemTmpFree(pszFreeMe);
+ return rc;
+}
+
+
+/**
+ * Consults enviornment variables that cURL/lynx/wget/lynx uses for figuring out
+ * the proxy config.
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL to configure a proxy for.
+ */
+static int rtHttpConfigureProxyForUrlFromEnv(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ char szTmp[_1K];
+
+ /*
+ * First we consult the "no_proxy" / "NO_PROXY" environment variable.
+ */
+ const char *pszNoProxyVar;
+ size_t cchActual;
+ char *pszNoProxyFree = NULL;
+ char *pszNoProxy = szTmp;
+ int rc = RTEnvGetEx(RTENV_DEFAULT, pszNoProxyVar = "no_proxy", szTmp, sizeof(szTmp), &cchActual);
+ if (rc == VERR_ENV_VAR_NOT_FOUND)
+ rc = RTEnvGetEx(RTENV_DEFAULT, pszNoProxyVar = "NO_PROXY", szTmp, sizeof(szTmp), &cchActual);
+ if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ pszNoProxyFree = pszNoProxy = (char *)RTMemTmpAlloc(cchActual + _1K);
+ AssertReturn(pszNoProxy, VERR_NO_TMP_MEMORY);
+ rc = RTEnvGetEx(RTENV_DEFAULT, pszNoProxyVar, pszNoProxy, cchActual + _1K, NULL);
+ }
+ AssertMsg(rc == VINF_SUCCESS || rc == VERR_ENV_VAR_NOT_FOUND, ("rc=%Rrc\n", rc));
+ bool fNoProxy = rtHttpUrlInNoProxyList(pszUrl, RTStrStrip(pszNoProxy));
+ RTMemTmpFree(pszNoProxyFree);
+ if (!fNoProxy)
+ {
+ /*
+ * Get the schema specific specific env var, falling back on the
+ * generic all_proxy if not found.
+ */
+ const char *apszEnvVars[4];
+ unsigned cEnvVars = 0;
+ if (!RTStrNICmp(pszUrl, RT_STR_TUPLE("http:")))
+ apszEnvVars[cEnvVars++] = "http_proxy"; /* Skip HTTP_PROXY because of cgi paranoia */
+ else if (!RTStrNICmp(pszUrl, RT_STR_TUPLE("https:")))
+ {
+ apszEnvVars[cEnvVars++] = "https_proxy";
+ apszEnvVars[cEnvVars++] = "HTTPS_PROXY";
+ }
+ else if (!RTStrNICmp(pszUrl, RT_STR_TUPLE("ftp:")))
+ {
+ apszEnvVars[cEnvVars++] = "ftp_proxy";
+ apszEnvVars[cEnvVars++] = "FTP_PROXY";
+ }
+ else
+ AssertMsgFailedReturn(("Unknown/unsupported schema in URL: '%s'\n", pszUrl), VERR_NOT_SUPPORTED);
+ apszEnvVars[cEnvVars++] = "all_proxy";
+ apszEnvVars[cEnvVars++] = "ALL_PROXY";
+
+ /*
+ * We try the env vars out and goes with the first one we can make sense out of.
+ * If we cannot make sense of any, we return the first unexpected rc we got.
+ */
+ rc = VINF_SUCCESS;
+ for (uint32_t i = 0; i < cEnvVars; i++)
+ {
+ size_t cchValue;
+ int rc2 = RTEnvGetEx(RTENV_DEFAULT, apszEnvVars[i], szTmp, sizeof(szTmp) - sizeof("http://"), &cchValue);
+ if (RT_SUCCESS(rc2))
+ {
+ if (cchValue != 0)
+ {
+ /* Add a http:// prefix so RTUriParse groks it (cheaper to do it here). */
+ if (!strstr(szTmp, "://"))
+ {
+ memmove(&szTmp[sizeof("http://") - 1], szTmp, cchValue + 1);
+ memcpy(szTmp, RT_STR_TUPLE("http://"));
+ }
+
+ rc2 = rtHttpConfigureProxyFromUrl(pThis, szTmp);
+ if (RT_SUCCESS(rc2))
+ rc = rc2;
+ }
+ /*
+ * The variable is empty. Guess that means no proxying wanted.
+ */
+ else
+ {
+ rc = rtHttpUpdateAutomaticProxyDisable(pThis);
+ break;
+ }
+ }
+ else
+ AssertMsgStmt(rc2 == VERR_ENV_VAR_NOT_FOUND, ("%Rrc\n", rc2), if (RT_SUCCESS(rc)) rc = rc2);
+ }
+ }
+ /*
+ * The host is the no-proxy list, it seems.
+ */
+ else
+ rc = rtHttpUpdateAutomaticProxyDisable(pThis);
+
+ return rc;
+}
+
+#ifdef IPRT_USE_LIBPROXY
+
+/**
+ * @callback_method_impl{FNRTONCE,
+ * Attempts to load libproxy.so.1 and resolves APIs}
+ */
+static DECLCALLBACK(int) rtHttpLibProxyResolveImports(void *pvUser)
+{
+ RTLDRMOD hMod;
+ int rc = RTLdrLoad("/usr/lib/libproxy.so.1", &hMod);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(hMod, "px_proxy_factory_new", (void **)&g_pfnLibProxyFactoryCtor);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "px_proxy_factory_free", (void **)&g_pfnLibProxyFactoryDtor);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "px_proxy_factory_get_proxies", (void **)&g_pfnLibProxyFactoryGetProxies);
+ if (RT_SUCCESS(rc))
+ g_hLdrLibProxy = hMod;
+ else
+ RTLdrClose(hMod);
+ AssertRC(rc);
+ }
+
+ NOREF(pvUser);
+ return rc;
+}
+
+/**
+ * Reconfigures the cURL proxy settings for the given URL, libproxy style.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if we should try fallback.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL.
+ */
+static int rtHttpLibProxyConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ int rcRet = VINF_NOT_SUPPORTED;
+
+ int rc = RTOnce(&g_LibProxyResolveImportsOnce, rtHttpLibProxyResolveImports, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Instance the factory and ask for a list of proxies.
+ */
+ PLIBPROXYFACTORY pFactory = g_pfnLibProxyFactoryCtor();
+ if (pFactory)
+ {
+ char **papszProxies = g_pfnLibProxyFactoryGetProxies(pFactory, pszUrl);
+ g_pfnLibProxyFactoryDtor(pFactory);
+ if (papszProxies)
+ {
+ /*
+ * Look for something we can use.
+ */
+ for (unsigned i = 0; papszProxies[i]; i++)
+ {
+ if (strncmp(papszProxies[i], RT_STR_TUPLE("direct://")) == 0)
+ rcRet = rtHttpUpdateAutomaticProxyDisable(pThis);
+ else if ( strncmp(papszProxies[i], RT_STR_TUPLE("http://")) == 0
+ || strncmp(papszProxies[i], RT_STR_TUPLE("socks5://")) == 0
+ || strncmp(papszProxies[i], RT_STR_TUPLE("socks4://")) == 0
+ || strncmp(papszProxies[i], RT_STR_TUPLE("socks://")) == 0 /** @todo same problem as on OS X. */
+ )
+ rcRet = rtHttpConfigureProxyFromUrl(pThis, papszProxies[i]);
+ else
+ continue;
+ if (rcRet != VINF_NOT_SUPPORTED)
+ break;
+ }
+
+ /* free the result. */
+ for (unsigned i = 0; papszProxies[i]; i++)
+ free(papszProxies[i]);
+ free(papszProxies);
+ }
+ }
+ }
+
+ return rcRet;
+}
+
+#endif /* IPRT_USE_LIBPROXY */
+
+#ifdef RT_OS_DARWIN
+
+/**
+ * Get a boolean like integer value from a dictionary.
+ *
+ * @returns true / false.
+ * @param hDict The dictionary.
+ * @param pvKey The dictionary value key.
+ */
+static bool rtHttpDarwinGetBooleanFromDict(CFDictionaryRef hDict, void const *pvKey, bool fDefault)
+{
+ CFNumberRef hNum = (CFNumberRef)CFDictionaryGetValue(hDict, pvKey);
+ if (hNum)
+ {
+ int fEnabled;
+ if (!CFNumberGetValue(hNum, kCFNumberIntType, &fEnabled))
+ return fDefault;
+ return fEnabled != 0;
+ }
+ return fDefault;
+}
+
+
+/**
+ * Creates a CFURL object for an URL.
+ *
+ * @returns CFURL object reference.
+ * @param pszUrl The URL.
+ */
+static CFURLRef rtHttpDarwinUrlToCFURL(const char *pszUrl)
+{
+ CFURLRef hUrl = NULL;
+ CFStringRef hStrUrl = CFStringCreateWithCString(kCFAllocatorDefault, pszUrl, kCFStringEncodingUTF8);
+ if (hStrUrl)
+ {
+ CFStringRef hStrUrlEscaped = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, hStrUrl,
+ NULL /*charactersToLeaveUnescaped*/,
+ NULL /*legalURLCharactersToBeEscaped*/,
+ kCFStringEncodingUTF8);
+ if (hStrUrlEscaped)
+ {
+ hUrl = CFURLCreateWithString(kCFAllocatorDefault, hStrUrlEscaped, NULL /*baseURL*/);
+ Assert(hUrl);
+ CFRelease(hStrUrlEscaped);
+ }
+ else
+ AssertFailed();
+ CFRelease(hStrUrl);
+ }
+ else
+ AssertFailed();
+ return hUrl;
+}
+
+
+/**
+ * For passing results from rtHttpDarwinPacCallback to
+ * rtHttpDarwinExecuteProxyAutoConfigurationUrl.
+ */
+typedef struct RTHTTPDARWINPACRESULT
+{
+ CFArrayRef hArrayProxies;
+ CFErrorRef hError;
+} RTHTTPDARWINPACRESULT;
+typedef RTHTTPDARWINPACRESULT *PRTHTTPDARWINPACRESULT;
+
+/**
+ * Stupid callback for getting the result from
+ * CFNetworkExecuteProxyAutoConfigurationURL.
+ *
+ * @param pvUser Pointer to a RTHTTPDARWINPACRESULT on the stack of
+ * rtHttpDarwinExecuteProxyAutoConfigurationUrl.
+ * @param hArrayProxies The result array.
+ * @param hError Errors, if any.
+ */
+static void rtHttpDarwinPacCallback(void *pvUser, CFArrayRef hArrayProxies, CFErrorRef hError)
+{
+ PRTHTTPDARWINPACRESULT pResult = (PRTHTTPDARWINPACRESULT)pvUser;
+
+ Assert(pResult->hArrayProxies == NULL);
+ if (hArrayProxies)
+ pResult->hArrayProxies = (CFArrayRef)CFRetain(hArrayProxies);
+
+ Assert(pResult->hError == NULL);
+ if (hError)
+ pResult->hError = (CFErrorRef)CFRetain(hError);
+
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+
+/**
+ * Executes a PAC script and returning the proxies it suggests.
+ *
+ * @returns Array of proxy configs (CFProxySupport.h style).
+ * @param pThis The HTTP client instance.
+ * @param hUrlTarget The URL we're about to use.
+ * @param hUrlScript The PAC script URL.
+ */
+static CFArrayRef rtHttpDarwinExecuteProxyAutoConfigurationUrl(PRTHTTPINTERNAL pThis, CFURLRef hUrlTarget, CFURLRef hUrlScript)
+{
+ char szTmp[256];
+ if (LogIsFlowEnabled())
+ {
+ szTmp[0] = '\0';
+ CFStringGetCString(CFURLGetString(hUrlScript), szTmp, sizeof(szTmp), kCFStringEncodingUTF8);
+ LogFlow(("rtHttpDarwinExecuteProxyAutoConfigurationUrl: hUrlScript=%p:%s\n", hUrlScript, szTmp));
+ }
+
+ /*
+ * Use CFNetworkExecuteProxyAutoConfigurationURL here so we don't have to
+ * download the script ourselves and mess around with too many CF APIs.
+ */
+ CFRunLoopRef hRunLoop = CFRunLoopGetCurrent();
+ AssertReturn(hRunLoop, NULL);
+
+ RTHTTPDARWINPACRESULT Result = { NULL, NULL };
+ CFStreamClientContext Ctx = { 0, &Result, NULL, NULL, NULL };
+ CFRunLoopSourceRef hRunLoopSrc = CFNetworkExecuteProxyAutoConfigurationURL(hUrlScript, hUrlTarget,
+ rtHttpDarwinPacCallback, &Ctx);
+ AssertReturn(hRunLoopSrc, NULL);
+
+ CFStringRef kMode = CFSTR("com.apple.dts.CFProxySupportTool");
+ CFRunLoopAddSource(hRunLoop, hRunLoopSrc, kMode);
+ CFRunLoopRunInMode(kMode, 1.0e10, false); /* callback will force a return. */
+ CFRunLoopRemoveSource(hRunLoop, hRunLoopSrc, kMode);
+
+ /** @todo convert errors, maybe even fail. */
+
+ /*
+ * Autoconfig (or missing wpad server) typically results in:
+ * domain:kCFErrorDomainCFNetwork; code=kCFHostErrorUnknown (2).
+ *
+ * In the autoconfig case, it looks like we're getting two entries, first
+ * one that's http://wpad/wpad.dat and a noproxy entry. So, no reason to
+ * be very upset if this fails, just continue trying alternatives.
+ */
+ if (Result.hError)
+ {
+ if (LogIsEnabled())
+ {
+ szTmp[0] = '\0';
+ CFStringGetCString(CFErrorCopyDescription(Result.hError), szTmp, sizeof(szTmp), kCFStringEncodingUTF8);
+ Log(("rtHttpDarwinExecuteProxyAutoConfigurationUrl: error! code=%ld desc='%s'\n", (long)CFErrorGetCode(Result.hError), szTmp));
+ }
+ CFRelease(Result.hError);
+ }
+ return Result.hArrayProxies;
+}
+
+
+/**
+ * Attempt to configure the proxy according to @a hDictProxy.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if not able to configure it and
+ * the caller should try out alternative proxy configs and fallbacks.
+ * @param pThis The HTTP client instance.
+ * @param hDictProxy The proxy configuration (see CFProxySupport.h).
+ * @param hUrlTarget The URL we're about to use.
+ * @param fIgnorePacType Whether to ignore PAC type proxy entries (i.e.
+ * javascript URL). This is set when we're processing
+ * the output from a PAC script.
+ */
+static int rtHttpDarwinTryConfigProxy(PRTHTTPINTERNAL pThis, CFDictionaryRef hDictProxy, CFURLRef hUrlTarget, bool fIgnorePacType)
+{
+ CFStringRef hStrProxyType = (CFStringRef)CFDictionaryGetValue(hDictProxy, kCFProxyTypeKey);
+ AssertStmt(hStrProxyType, continue);
+
+ /*
+ * No proxy is fairly simple and common.
+ */
+ if (CFEqual(hStrProxyType, kCFProxyTypeNone))
+ return rtHttpUpdateAutomaticProxyDisable(pThis);
+
+ /*
+ * PAC URL means recursion, however we only do one level.
+ */
+ if (CFEqual(hStrProxyType, kCFProxyTypeAutoConfigurationURL))
+ {
+ AssertReturn(!fIgnorePacType, VINF_NOT_SUPPORTED);
+
+ CFURLRef hUrlScript = (CFURLRef)CFDictionaryGetValue(hDictProxy, kCFProxyAutoConfigurationURLKey);
+ AssertReturn(hUrlScript, VINF_NOT_SUPPORTED);
+
+ int rcRet = VINF_NOT_SUPPORTED;
+ CFArrayRef hArray = rtHttpDarwinExecuteProxyAutoConfigurationUrl(pThis, hUrlTarget, hUrlScript);
+ if (hArray)
+ {
+ rcRet = rtHttpDarwinTryConfigProxies(pThis, hArray, hUrlTarget, true /*fIgnorePacType*/);
+ CFRelease(hArray);
+ }
+ return rcRet;
+ }
+
+ /*
+ * Determine the proxy type (not entirely sure about type == proxy type and
+ * not scheme/protocol)...
+ */
+ curl_proxytype enmProxyType = CURLPROXY_HTTP;
+ uint32_t uDefaultProxyPort = 8080;
+ if ( CFEqual(hStrProxyType, kCFProxyTypeHTTP)
+ || CFEqual(hStrProxyType, kCFProxyTypeHTTPS))
+ { /* defaults */ }
+ else if (CFEqual(hStrProxyType, kCFProxyTypeSOCKS))
+ {
+ /** @todo All we get from darwin is 'SOCKS', no idea whether it's SOCK4 or
+ * SOCK5 on the other side... Selecting SOCKS5 for now. */
+ enmProxyType = CURLPROXY_SOCKS5;
+ uDefaultProxyPort = 1080;
+ }
+ /* Unknown proxy type. */
+ else
+ return VINF_NOT_SUPPORTED;
+
+ /*
+ * Extract the proxy configuration.
+ */
+ /* The proxy host name. */
+ char szHostname[_1K];
+ CFStringRef hStr = (CFStringRef)CFDictionaryGetValue(hDictProxy, kCFProxyHostNameKey);
+ AssertReturn(hStr, VINF_NOT_SUPPORTED);
+ AssertReturn(CFStringGetCString(hStr, szHostname, sizeof(szHostname), kCFStringEncodingUTF8), VINF_NOT_SUPPORTED);
+
+ /* Get the port number (optional). */
+ SInt32 iProxyPort;
+ CFNumberRef hNum = (CFNumberRef)CFDictionaryGetValue(hDictProxy, kCFProxyPortNumberKey);
+ if (hNum && CFNumberGetValue(hNum, kCFNumberSInt32Type, &iProxyPort))
+ AssertMsgStmt(iProxyPort > 0 && iProxyPort < _64K, ("%d\n", iProxyPort), iProxyPort = uDefaultProxyPort);
+ else
+ iProxyPort = uDefaultProxyPort;
+
+ /* The proxy username. */
+ char szUsername[256];
+ hStr = (CFStringRef)CFDictionaryGetValue(hDictProxy, kCFProxyUsernameKey);
+ if (hStr)
+ AssertReturn(CFStringGetCString(hStr, szUsername, sizeof(szUsername), kCFStringEncodingUTF8), VINF_NOT_SUPPORTED);
+ else
+ szUsername[0] = '\0';
+
+ /* The proxy password. */
+ char szPassword[384];
+ hStr = (CFStringRef)CFDictionaryGetValue(hDictProxy, kCFProxyPasswordKey);
+ if (hStr)
+ AssertReturn(CFStringGetCString(hStr, szPassword, sizeof(szPassword), kCFStringEncodingUTF8), VINF_NOT_SUPPORTED);
+ else
+ szPassword[0] = '\0';
+
+ /*
+ * Apply the proxy config.
+ */
+ return rtHttpUpdateProxyConfig(pThis, enmProxyType, szHostname, iProxyPort,
+ szUsername[0] ? szUsername : NULL, szPassword[0] ? szPassword : NULL);
+}
+
+
+/**
+ * Try do proxy config for our HTTP client instance given an array of proxies.
+ *
+ * This is used with the output from a CFProxySupport.h API.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if not able to configure it and
+ * we might want to try out fallbacks.
+ * @param pThis The HTTP client instance.
+ * @param hArrayProxies The proxies CFPRoxySupport have given us.
+ * @param hUrlTarget The URL we're about to use.
+ * @param fIgnorePacType Whether to ignore PAC type proxy entries (i.e.
+ * javascript URL). This is set when we're processing
+ * the output from a PAC script.
+ */
+static int rtHttpDarwinTryConfigProxies(PRTHTTPINTERNAL pThis, CFArrayRef hArrayProxies, CFURLRef hUrlTarget, bool fIgnorePacType)
+{
+ int rcRet = VINF_NOT_SUPPORTED;
+ CFIndex const cEntries = CFArrayGetCount(hArrayProxies);
+ LogFlow(("rtHttpDarwinTryConfigProxies: cEntries=%d\n", cEntries));
+ for (CFIndex i = 0; i < cEntries; i++)
+ {
+ CFDictionaryRef hDictProxy = (CFDictionaryRef)CFArrayGetValueAtIndex(hArrayProxies, i);
+ AssertStmt(hDictProxy, continue);
+
+ rcRet = rtHttpDarwinTryConfigProxy(pThis, hDictProxy, hUrlTarget, fIgnorePacType);
+ if (rcRet != VINF_NOT_SUPPORTED)
+ break;
+ }
+ return rcRet;
+}
+
+
+/**
+ * Inner worker for rtHttpWinConfigureProxyForUrl.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if we should try fallback.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL.
+ */
+static int rtHttpDarwinConfigureProxyForUrlWorker(PRTHTTPINTERNAL pThis, CFDictionaryRef hDictProxies,
+ const char *pszUrl, PRTURIPARSED pParsed, const char *pszHost)
+{
+ CFArrayRef hArray;
+
+ /*
+ * From what I can tell, the CFNetworkCopyProxiesForURL API doesn't apply
+ * proxy exclusion rules (tested on 10.9). So, do that manually.
+ */
+ RTNETADDRU HostAddr;
+ int fIsHostIpv4Address = -1;
+ char szTmp[_4K];
+
+ /* If we've got a simple hostname, something containing no dots, we must check
+ whether such simple hostnames are excluded from proxying by default or not. */
+ if (strchr(pszHost, '.') == NULL)
+ {
+ if (rtHttpDarwinGetBooleanFromDict(hDictProxies, kSCPropNetProxiesExcludeSimpleHostnames, false))
+ return rtHttpUpdateAutomaticProxyDisable(pThis);
+ fIsHostIpv4Address = false;
+ }
+
+ /* Consult the exclusion list. This is an array of strings.
+ This is very similar to what we do on windows. */
+ hArray = (CFArrayRef)CFDictionaryGetValue(hDictProxies, kSCPropNetProxiesExceptionsList);
+ if (hArray)
+ {
+ CFIndex const cEntries = CFArrayGetCount(hArray);
+ for (CFIndex i = 0; i < cEntries; i++)
+ {
+ CFStringRef hStr = (CFStringRef)CFArrayGetValueAtIndex(hArray, i);
+ AssertStmt(hStr, continue);
+ AssertStmt(CFStringGetCString(hStr, szTmp, sizeof(szTmp), kCFStringEncodingUTF8), continue);
+ RTStrToLower(szTmp);
+
+ bool fRet;
+ if ( strchr(szTmp, '*')
+ || strchr(szTmp, '?'))
+ fRet = RTStrSimplePatternMatch(szTmp, pszHost);
+ else
+ {
+ if (fIsHostIpv4Address == -1)
+ fIsHostIpv4Address = RT_SUCCESS(RTNetStrToIPv4Addr(pszHost, &HostAddr.IPv4));
+ RTNETADDRIPV4 Network, Netmask;
+ if ( fIsHostIpv4Address
+ && RT_SUCCESS(RTCidrStrToIPv4(szTmp, &Network, &Netmask)) )
+ fRet = (HostAddr.IPv4.u & Netmask.u) == Network.u;
+ else
+ fRet = strcmp(szTmp, pszHost) == 0;
+ }
+ if (fRet)
+ return rtHttpUpdateAutomaticProxyDisable(pThis);
+ }
+ }
+
+#if 0 /* The start of a manual alternative to CFNetworkCopyProxiesForURL below, hopefully we won't need this. */
+ /*
+ * Is proxy auto config (PAC) enabled? If so, we must consult it first.
+ */
+ if (rtHttpDarwinGetBooleanFromDict(hDictProxies, kSCPropNetProxiesProxyAutoConfigEnable, false))
+ {
+ /* Convert the auto config url string to a CFURL object. */
+ CFStringRef hStrAutoConfigUrl = (CFStringRef)CFDictionaryGetValue(hDictProxies, kSCPropNetProxiesProxyAutoConfigURLString);
+ if (hStrAutoConfigUrl)
+ {
+ if (CFStringGetCString(hStrAutoConfigUrl, szTmp, sizeof(szTmp), kCFStringEncodingUTF8))
+ {
+ CFURLRef hUrlScript = rtHttpDarwinUrlToCFURL(szTmp);
+ if (hUrlScript)
+ {
+ int rcRet = VINF_NOT_SUPPORTED;
+ CFURLRef hUrlTarget = rtHttpDarwinUrlToCFURL(pszUrl);
+ if (hUrlTarget)
+ {
+ /* Work around for <rdar://problem/5530166>, whatever that is. Initializes
+ some internal CFNetwork state, they say. See CFPRoxySupportTool example. */
+ hArray = CFNetworkCopyProxiesForURL(hUrlTarget, NULL);
+ if (hArray)
+ CFRelease(hArray);
+
+ hArray = rtHttpDarwinExecuteProxyAutoConfigurationUrl(pThis, hUrlTarget, hUrlScript);
+ if (hArray)
+ {
+ rcRet = rtHttpDarwinTryConfigProxies(pThis, hArray, hUrlTarget, true /*fIgnorePacType*/);
+ CFRelease(hArray);
+ }
+ }
+ CFRelease(hUrlScript);
+ if (rcRet != VINF_NOT_SUPPORTED)
+ return rcRet;
+ }
+ }
+ }
+ }
+
+ /*
+ * Try static proxy configs.
+ */
+ /** @todo later if needed. */
+ return VERR_NOT_SUPPORTED;
+
+#else
+ /*
+ * Simple solution - "just" use CFNetworkCopyProxiesForURL.
+ */
+ CFURLRef hUrlTarget = rtHttpDarwinUrlToCFURL(pszUrl);
+ AssertReturn(hUrlTarget, VERR_INTERNAL_ERROR);
+ int rcRet = VINF_NOT_SUPPORTED;
+
+ /* Work around for <rdar://problem/5530166>, whatever that is. Initializes
+ some internal CFNetwork state, they say. See CFPRoxySupportTool example. */
+ hArray = CFNetworkCopyProxiesForURL(hUrlTarget, NULL);
+ if (hArray)
+ CFRelease(hArray);
+
+ /* The actual run. */
+ hArray = CFNetworkCopyProxiesForURL(hUrlTarget, hDictProxies);
+ if (hArray)
+ {
+ rcRet = rtHttpDarwinTryConfigProxies(pThis, hArray, hUrlTarget, false /*fIgnorePacType*/);
+ CFRelease(hArray);
+ }
+ CFRelease(hUrlTarget);
+
+ return rcRet;
+#endif
+}
+
+/**
+ * Reconfigures the cURL proxy settings for the given URL, OS X style.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if we should try fallback.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL.
+ */
+static int rtHttpDarwinConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ /*
+ * Parse the URL, if there isn't any host name (like for file:///xxx.txt)
+ * we don't need to run thru proxy settings to know what to do.
+ */
+ RTURIPARSED Parsed;
+ int rc = RTUriParse(pszUrl, &Parsed);
+ AssertRCReturn(rc, false);
+ if (Parsed.cchAuthorityHost == 0)
+ return rtHttpUpdateAutomaticProxyDisable(pThis);
+ char *pszHost = RTUriParsedAuthorityHost(pszUrl, &Parsed);
+ AssertReturn(pszHost, VERR_NO_STR_MEMORY);
+ RTStrToLower(pszHost);
+
+ /*
+ * Get a copy of the proxy settings (10.6 API).
+ */
+ CFDictionaryRef hDictProxies = CFNetworkCopySystemProxySettings(); /* Alt for 10.5: SCDynamicStoreCopyProxies(NULL); */
+ if (hDictProxies)
+ rc = rtHttpDarwinConfigureProxyForUrlWorker(pThis, hDictProxies, pszUrl, &Parsed, pszHost);
+ else
+ rc = VINF_NOT_SUPPORTED;
+ CFRelease(hDictProxies);
+
+ RTStrFree(pszHost);
+ return rc;
+}
+
+#endif /* RT_OS_DARWIN */
+
+#ifdef RT_OS_WINDOWS
+
+/**
+ * @callback_method_impl{FNRTONCE, Loads WinHttp.dll and resolves APIs}
+ */
+static DECLCALLBACK(int) rtHttpWinResolveImports(void *pvUser)
+{
+ RTLDRMOD hMod;
+ int rc = RTLdrLoadSystem("winhttp.dll", true /*fNoUnload*/, &hMod);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(hMod, "WinHttpOpen", (void **)&g_pfnWinHttpOpen);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "WinHttpCloseHandle", (void **)&g_pfnWinHttpCloseHandle);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "WinHttpGetProxyForUrl", (void **)&g_pfnWinHttpGetProxyForUrl);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "WinHttpGetDefaultProxyConfiguration", (void **)&g_pfnWinHttpGetDefaultProxyConfiguration);
+ if (RT_SUCCESS(rc))
+ rc = RTLdrGetSymbol(hMod, "WinHttpGetIEProxyConfigForCurrentUser", (void **)&g_pfnWinHttpGetIEProxyConfigForCurrentUser);
+ RTLdrClose(hMod);
+ }
+ AssertRC(rc);
+
+ NOREF(pvUser);
+ return rc;
+}
+
+
+/**
+ * Matches the URL against the given Windows by-pass list.
+ *
+ * @returns true if we should by-pass the proxy for this URL, false if not.
+ * @param pszUrl The URL.
+ * @param pwszBypass The Windows by-pass list.
+ */
+static bool rtHttpWinIsUrlInBypassList(const char *pszUrl, PCRTUTF16 pwszBypass)
+{
+ /*
+ * Don't bother parsing the URL if we've actually got nothing to work with
+ * in the by-pass list.
+ */
+ if (!pwszBypass)
+ return false;
+
+ RTUTF16 wc;
+ while ( (wc = *pwszBypass) != '\0'
+ && ( RTUniCpIsSpace(wc)
+ || wc == ';') )
+ pwszBypass++;
+ if (wc == '\0')
+ return false;
+
+ /*
+ * We now need to parse the URL and extract the host name.
+ */
+ RTURIPARSED Parsed;
+ int rc = RTUriParse(pszUrl, &Parsed);
+ AssertRCReturn(rc, false);
+ char *pszHost = RTUriParsedAuthorityHost(pszUrl, &Parsed);
+ if (!pszHost) /* Don't assert, in case of file:///xxx or similar blunder. */
+ return false;
+ RTStrToLower(pszHost);
+
+ bool fRet = false;
+ char *pszBypassFree;
+ rc = RTUtf16ToUtf8(pwszBypass, &pszBypassFree);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Walk the by-pass list.
+ *
+ * According to https://msdn.microsoft.com/en-us/library/aa384098(v=vs.85).aspx
+ * a by-pass list is semicolon delimited list. The entries are either host
+ * names or IP addresses, and may use wildcard ('*', '?', I guess). There
+ * special "<local>" entry matches anything without a dot.
+ */
+ RTNETADDRU HostAddr;
+ int fIsHostIpv4Address = -1;
+ char *pszEntry = pszBypassFree;
+ while (*pszEntry != '\0')
+ {
+ /*
+ * Find end of entry.
+ */
+ char ch;
+ size_t cchEntry = 1;
+ while ( (ch = pszEntry[cchEntry]) != '\0'
+ && ch != ';'
+ && !RT_C_IS_SPACE(ch))
+ cchEntry++;
+
+ char chSaved = pszEntry[cchEntry];
+ pszEntry[cchEntry] = '\0';
+ RTStrToLower(pszEntry);
+
+ if ( cchEntry == sizeof("<local>") - 1
+ && memcmp(pszEntry, RT_STR_TUPLE("<local>")) == 0)
+ fRet = strchr(pszHost, '.') == NULL;
+ else if ( memchr(pszEntry, '*', cchEntry) != NULL
+ || memchr(pszEntry, '?', cchEntry) != NULL)
+ fRet = RTStrSimplePatternMatch(pszEntry, pszHost);
+ else
+ {
+ if (fIsHostIpv4Address == -1)
+ fIsHostIpv4Address = RT_SUCCESS(RTNetStrToIPv4Addr(pszHost, &HostAddr.IPv4));
+ RTNETADDRIPV4 Network, Netmask;
+ if ( fIsHostIpv4Address
+ && RT_SUCCESS(RTCidrStrToIPv4(pszEntry, &Network, &Netmask)) )
+ fRet = (HostAddr.IPv4.u & Netmask.u) == Network.u;
+ else
+ fRet = strcmp(pszEntry, pszHost) == 0;
+ }
+
+ pszEntry[cchEntry] = chSaved;
+ if (fRet)
+ break;
+
+ /*
+ * Next entry.
+ */
+ pszEntry += cchEntry;
+ while ( (ch = *pszEntry) != '\0'
+ && ( ch == ';'
+ || RT_C_IS_SPACE(ch)) )
+ pszEntry++;
+ }
+
+ RTStrFree(pszBypassFree);
+ }
+
+ RTStrFree(pszHost);
+ return false;
+}
+
+
+/**
+ * Searches a Windows proxy server list for the best fitting proxy to use, then
+ * reconfigures the HTTP client instance to use it.
+ *
+ * @returns IPRT status code, VINF_NOT_SUPPORTED if we need to consult fallback.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL needing proxying.
+ * @param pwszProxies The list of proxy servers to choose from.
+ */
+static int rtHttpWinSelectProxyFromList(PRTHTTPINTERNAL pThis, const char *pszUrl, PCRTUTF16 pwszProxies)
+{
+ /*
+ * Fend off empty strings (very unlikely, but just in case).
+ */
+ if (!pwszProxies)
+ return VINF_NOT_SUPPORTED;
+
+ RTUTF16 wc;
+ while ( (wc = *pwszProxies) != '\0'
+ && ( RTUniCpIsSpace(wc)
+ || wc == ';') )
+ pwszProxies++;
+ if (wc == '\0')
+ return VINF_NOT_SUPPORTED;
+
+ /*
+ * We now need to parse the URL and extract the scheme.
+ */
+ RTURIPARSED Parsed;
+ int rc = RTUriParse(pszUrl, &Parsed);
+ AssertRCReturn(rc, false);
+ char *pszUrlScheme = RTUriParsedScheme(pszUrl, &Parsed);
+ AssertReturn(pszUrlScheme, VERR_NO_STR_MEMORY);
+ size_t const cchUrlScheme = strlen(pszUrlScheme);
+
+ int rcRet = VINF_NOT_SUPPORTED;
+ char *pszProxiesFree;
+ rc = RTUtf16ToUtf8(pwszProxies, &pszProxiesFree);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Walk the server list.
+ *
+ * According to https://msdn.microsoft.com/en-us/library/aa383912(v=vs.85).aspx
+ * this is also a semicolon delimited list. The entries are on the form:
+ * [<scheme>=][<scheme>"://"]<server>[":"<port>]
+ */
+ bool fBestEntryHasSameScheme = false;
+ const char *pszBestEntry = NULL;
+ char *pszEntry = pszProxiesFree;
+ while (*pszEntry != '\0')
+ {
+ /*
+ * Find end of entry. We include spaces here in addition to ';'.
+ */
+ char ch;
+ size_t cchEntry = 1;
+ while ( (ch = pszEntry[cchEntry]) != '\0'
+ && ch != ';'
+ && !RT_C_IS_SPACE(ch))
+ cchEntry++;
+
+ char const chSaved = pszEntry[cchEntry];
+ pszEntry[cchEntry] = '\0';
+
+ /* Parse the entry. */
+ const char *pszEndOfScheme = strstr(pszEntry, "://");
+ const char *pszEqual = (const char *)memchr(pszEntry, '=',
+ pszEndOfScheme ? pszEndOfScheme - pszEntry : cchEntry);
+ if (pszEqual)
+ {
+ if ( pszEqual - pszEntry == cchUrlScheme
+ && RTStrNICmp(pszEntry, pszUrlScheme, cchUrlScheme) == 0)
+ {
+ pszBestEntry = pszEqual + 1;
+ break;
+ }
+ }
+ else
+ {
+ bool fSchemeMatch = pszEndOfScheme
+ && pszEndOfScheme - pszEntry == cchUrlScheme
+ && RTStrNICmp(pszEntry, pszUrlScheme, cchUrlScheme) == 0;
+ if ( !pszBestEntry
+ || ( !fBestEntryHasSameScheme
+ && fSchemeMatch) )
+ {
+ pszBestEntry = pszEntry;
+ fBestEntryHasSameScheme = fSchemeMatch;
+ }
+ }
+
+ /*
+ * Next entry.
+ */
+ if (!chSaved)
+ break;
+ pszEntry += cchEntry + 1;
+ while ( (ch = *pszEntry) != '\0'
+ && ( ch == ';'
+ || RT_C_IS_SPACE(ch)) )
+ pszEntry++;
+ }
+
+ /*
+ * If we found something, try use it.
+ */
+ if (pszBestEntry)
+ rcRet = rtHttpConfigureProxyFromUrl(pThis, pszBestEntry);
+
+ RTStrFree(pszProxiesFree);
+ }
+
+ RTStrFree(pszUrlScheme);
+ return rc;
+}
+
+
+/**
+ * Reconfigures the cURL proxy settings for the given URL, Windows style.
+ *
+ * @returns IPRT status code. VINF_NOT_SUPPORTED if we should try fallback.
+ * @param pThis The HTTP client instance.
+ * @param pszUrl The URL.
+ */
+static int rtHttpWinConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ int rcRet = VINF_NOT_SUPPORTED;
+
+ int rc = RTOnce(&g_WinResolveImportsOnce, rtHttpWinResolveImports, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Try get some proxy info for the URL. We first try getting the IE
+ * config and seeing if we can use WinHttpGetIEProxyConfigForCurrentUser
+ * in some way, if we can we prepare ProxyOptions with a non-zero dwFlags.
+ */
+ WINHTTP_PROXY_INFO ProxyInfo;
+ PRTUTF16 pwszProxy = NULL;
+ PRTUTF16 pwszNoProxy = NULL;
+ WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
+ RT_ZERO(AutoProxyOptions);
+ RT_ZERO(ProxyInfo);
+
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IeProxyConfig;
+ if (g_pfnWinHttpGetIEProxyConfigForCurrentUser(&IeProxyConfig))
+ {
+ AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
+ AutoProxyOptions.lpszAutoConfigUrl = IeProxyConfig.lpszAutoConfigUrl;
+ if (IeProxyConfig.fAutoDetect)
+ {
+ AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT | WINHTTP_AUTOPROXY_RUN_INPROCESS;
+ AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ }
+ else if (AutoProxyOptions.lpszAutoConfigUrl)
+ AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
+ else if (ProxyInfo.lpszProxy)
+ ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+ ProxyInfo.lpszProxy = IeProxyConfig.lpszProxy;
+ ProxyInfo.lpszProxyBypass = IeProxyConfig.lpszProxyBypass;
+ }
+ else
+ {
+ AssertMsgFailed(("WinHttpGetIEProxyConfigForCurrentUser -> %u\n", GetLastError()));
+ if (!g_pfnWinHttpGetDefaultProxyConfiguration(&ProxyInfo))
+ {
+ AssertMsgFailed(("WinHttpGetDefaultProxyConfiguration -> %u\n", GetLastError()));
+ RT_ZERO(ProxyInfo);
+ }
+ }
+
+ /*
+ * Should we try WinHttGetProxyForUrl?
+ */
+ if (AutoProxyOptions.dwFlags != 0)
+ {
+ HINTERNET hSession = g_pfnWinHttpOpen(NULL /*pwszUserAgent*/, WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 /*dwFlags*/ );
+ if (hSession != NULL)
+ {
+ PRTUTF16 pwszUrl;
+ rc = RTStrToUtf16(pszUrl, &pwszUrl);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Try autodetect first, then fall back on the config URL if there is one.
+ *
+ * Also, we first try without auto authentication, then with. This will according
+ * to http://msdn.microsoft.com/en-us/library/aa383153%28v=VS.85%29.aspx help with
+ * caching the result when it's processed out-of-process (seems default here on W10).
+ */
+ WINHTTP_PROXY_INFO TmpProxyInfo;
+ BOOL fRc = g_pfnWinHttpGetProxyForUrl(hSession, pwszUrl, &AutoProxyOptions, &TmpProxyInfo);
+ if ( !fRc
+ && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE)
+ {
+ AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
+ fRc = g_pfnWinHttpGetProxyForUrl(hSession, pwszUrl, &AutoProxyOptions, &TmpProxyInfo);
+ }
+
+ if ( !fRc
+ && AutoProxyOptions.dwFlags != WINHTTP_AUTOPROXY_CONFIG_URL
+ && AutoProxyOptions.lpszAutoConfigUrl)
+ {
+ AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
+ AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
+ AutoProxyOptions.dwAutoDetectFlags = 0;
+ fRc = g_pfnWinHttpGetProxyForUrl(hSession, pwszUrl, &AutoProxyOptions, &TmpProxyInfo);
+ if ( !fRc
+ && GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE)
+ {
+ AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
+ fRc = g_pfnWinHttpGetProxyForUrl(hSession, pwszUrl, &AutoProxyOptions, &TmpProxyInfo);
+ }
+ }
+
+ if (fRc)
+ {
+ if (ProxyInfo.lpszProxy)
+ GlobalFree(ProxyInfo.lpszProxy);
+ if (ProxyInfo.lpszProxyBypass)
+ GlobalFree(ProxyInfo.lpszProxyBypass);
+ ProxyInfo = TmpProxyInfo;
+ }
+ /*
+ * If the autodetection failed, assume no proxy.
+ */
+ else
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_WINHTTP_AUTODETECTION_FAILED)
+ rcRet = rtHttpUpdateAutomaticProxyDisable(pThis);
+ else
+ AssertMsgFailed(("g_pfnWinHttpGetProxyForUrl -> %u\n", dwErr));
+ }
+ RTUtf16Free(pwszUrl);
+ }
+ else
+ {
+ AssertMsgFailed(("RTStrToUtf16(%s,) -> %Rrc\n", pszUrl, rc));
+ rcRet = rc;
+ }
+ g_pfnWinHttpCloseHandle(hSession);
+ }
+ else
+ AssertMsgFailed(("g_pfnWinHttpOpen -> %u\n", GetLastError()));
+ }
+
+ /*
+ * Try use the proxy info we've found.
+ */
+ switch (ProxyInfo.dwAccessType)
+ {
+ case WINHTTP_ACCESS_TYPE_NO_PROXY:
+ rcRet = rtHttpUpdateAutomaticProxyDisable(pThis);
+ break;
+
+ case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
+ if (!rtHttpWinIsUrlInBypassList(pszUrl, ProxyInfo.lpszProxyBypass))
+ rcRet = rtHttpWinSelectProxyFromList(pThis, pszUrl, ProxyInfo.lpszProxy);
+ else
+ rcRet = rtHttpUpdateAutomaticProxyDisable(pThis);
+ break;
+
+ case 0:
+ break;
+
+ default:
+ AssertMsgFailed(("%#x\n", ProxyInfo.dwAccessType));
+ }
+
+ /*
+ * Cleanup.
+ */
+ if (ProxyInfo.lpszProxy)
+ GlobalFree(ProxyInfo.lpszProxy);
+ if (ProxyInfo.lpszProxyBypass)
+ GlobalFree(ProxyInfo.lpszProxyBypass);
+ if (AutoProxyOptions.lpszAutoConfigUrl)
+ GlobalFree((PRTUTF16)AutoProxyOptions.lpszAutoConfigUrl);
+ }
+
+ return rcRet;
+}
+
+#endif /* RT_OS_WINDOWS */
+
+
+static int rtHttpConfigureProxyForUrl(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ if (pThis->fUseSystemProxySettings)
+ {
+#ifdef IPRT_USE_LIBPROXY
+ int rc = rtHttpLibProxyConfigureProxyForUrl(pThis, pszUrl);
+ if (rc == VINF_SUCCESS || RT_FAILURE(rc))
+ return rc;
+ Assert(rc == VINF_NOT_SUPPORTED);
+#endif
+#ifdef RT_OS_DARWIN
+ int rc = rtHttpDarwinConfigureProxyForUrl(pThis, pszUrl);
+ if (rc == VINF_SUCCESS || RT_FAILURE(rc))
+ return rc;
+ Assert(rc == VINF_NOT_SUPPORTED);
+#endif
+#ifdef RT_OS_WINDOWS
+ int rc = rtHttpWinConfigureProxyForUrl(pThis, pszUrl);
+ if (rc == VINF_SUCCESS || RT_FAILURE(rc))
+ return rc;
+ Assert(rc == VINF_NOT_SUPPORTED);
+#endif
+/** @todo system specific class here, fall back on env vars if necessary. */
+ return rtHttpConfigureProxyForUrlFromEnv(pThis, pszUrl);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
+ const char *pcszProxyUser, const char *pcszProxyPwd)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+ AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
+ AssertReturn(!pThis->fBusy, VERR_WRONG_ORDER);
+
+ /*
+ * Update the settings.
+ *
+ * Currently, we don't make alot of effort parsing or checking the input, we
+ * leave that to cURL. (A bit afraid of breaking user settings.)
+ */
+ pThis->fUseSystemProxySettings = false;
+ return rtHttpUpdateProxyConfig(pThis, CURLPROXY_HTTP, pcszProxy, uPort ? uPort : 1080, pcszProxyUser, pcszProxyPwd);
+}
+
+
+RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ pThis->fHaveUserAgentHeader = false;
+ if (!cHeaders)
+ {
+ if (pThis->pHeaders)
+ curl_slist_free_all(pThis->pHeaders);
+ pThis->pHeaders = 0;
+ return VINF_SUCCESS;
+ }
+
+ struct curl_slist *pHeaders = NULL;
+ for (size_t i = 0; i < cHeaders; i++)
+ {
+ pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
+ if (strncmp(papszHeaders[i], RT_STR_TUPLE("User-Agent:")) == 0)
+ pThis->fHaveUserAgentHeader = true;
+ }
+
+ pThis->pHeaders = pHeaders;
+ int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pHeaders);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Unset the user agent if it's in one of the headers.
+ */
+ if ( pThis->fHaveUserAgentHeader
+ && pThis->fHaveSetUserAgent)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_USERAGENT, (char *)NULL);
+ Assert(CURL_SUCCESS(rcCurl));
+ pThis->fHaveSetUserAgent = false;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Set the CA file to NULL, deleting any temporary file if necessary.
+ *
+ * @param pThis The HTTP/HTTPS client instance.
+ */
+static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis)
+{
+ if (pThis->pszCaFile)
+ {
+ if (pThis->fDeleteCaFile)
+ {
+ int rc2 = RTFileDelete(pThis->pszCaFile);
+ AssertMsg(RT_SUCCESS(rc2) || !RTFileExists(pThis->pszCaFile), ("rc=%Rrc '%s'\n", rc2, pThis->pszCaFile));
+ }
+ RTStrFree(pThis->pszCaFile);
+ pThis->pszCaFile = NULL;
+ }
+}
+
+
+RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCaFile)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ rtHttpUnsetCaFile(pThis);
+
+ pThis->fDeleteCaFile = false;
+ if (pszCaFile)
+ return RTStrDupEx(&pThis->pszCaFile, pszCaFile);
+ return VINF_SUCCESS;
+}
+
+
+RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ /*
+ * Create a temporary file.
+ */
+ int rc = VERR_NO_STR_MEMORY;
+ char *pszCaFile = RTStrAlloc(RTPATH_MAX);
+ if (pszCaFile)
+ {
+ RTFILE hFile;
+ rc = RTFileOpenTemp(&hFile, pszCaFile, RTPATH_MAX,
+ RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Gather certificates into a temporary store and export them to the temporary file.
+ */
+ RTCRSTORE hStore;
+ rc = RTCrStoreCreateInMem(&hStore, 256);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTHttpGatherCaCertsInStore(hStore, 0 /*fFlags*/, pErrInfo);
+ if (RT_SUCCESS(rc))
+ /** @todo Consider adding an API for exporting to a RTFILE... */
+ rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
+ RTCrStoreRelease(hStore);
+ }
+ RTFileClose(hFile);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Set the CA file for the instance.
+ */
+ rtHttpUnsetCaFile(pThis);
+
+ pThis->fDeleteCaFile = true;
+ pThis->pszCaFile = pszCaFile;
+ return VINF_SUCCESS;
+ }
+
+ int rc2 = RTFileDelete(pszCaFile);
+ AssertRC(rc2);
+ }
+ else
+ RTErrInfoAddF(pErrInfo, rc, "Error creating temorary file: %Rrc", rc);
+
+ RTStrFree(pszCaFile);
+ }
+ return rc;
+}
+
+
+RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo)
+{
+ uint32_t const cBefore = RTCrStoreCertCount(hStore);
+ AssertReturn(cBefore != UINT32_MAX, VERR_INVALID_HANDLE);
+
+ /*
+ * Add the user store, quitely ignoring any errors.
+ */
+ RTCRSTORE hSrcStore;
+ int rcUser = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
+ if (RT_SUCCESS(rcUser))
+ {
+ rcUser = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ hSrcStore);
+ RTCrStoreRelease(hSrcStore);
+ }
+
+ /*
+ * Ditto for the system store.
+ */
+ int rcSystem = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
+ if (RT_SUCCESS(rcSystem))
+ {
+ rcSystem = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ hSrcStore);
+ RTCrStoreRelease(hSrcStore);
+ }
+
+ /*
+ * If the number of certificates increased, we consider it a success.
+ */
+ if (RTCrStoreCertCount(hStore) > cBefore)
+ {
+ if (RT_FAILURE(rcSystem))
+ return -rcSystem;
+ if (RT_FAILURE(rcUser))
+ return -rcUser;
+ return rcSystem != VINF_SUCCESS ? rcSystem : rcUser;
+ }
+
+ if (RT_FAILURE(rcSystem))
+ return rcSystem;
+ if (RT_FAILURE(rcUser))
+ return rcUser;
+ return VERR_NOT_FOUND;
+}
+
+
+RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo)
+{
+ RTCRSTORE hStore;
+ int rc = RTCrStoreCreateInMem(&hStore, 256);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTHttpGatherCaCertsInStore(hStore, fFlags, pErrInfo);
+ if (RT_SUCCESS(rc))
+ rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
+ RTCrStoreRelease(hStore);
+ }
+ return rc;
+}
+
+
+
+/**
+ * Figures out the IPRT status code for a GET.
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP/HTTPS client instance.
+ * @param rcCurl What curl returned.
+ */
+static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl)
+{
+ int rc = VERR_HTTP_CURL_ERROR;
+
+ if (pThis->pszRedirLocation)
+ {
+ RTStrFree(pThis->pszRedirLocation);
+ pThis->pszRedirLocation = NULL;
+ }
+ if (rcCurl == CURLE_OK)
+ {
+ curl_easy_getinfo(pThis->pCurl, CURLINFO_RESPONSE_CODE, &pThis->lLastResp);
+ switch (pThis->lLastResp)
+ {
+ case 200:
+ /* OK, request was fulfilled */
+ case 204:
+ /* empty response */
+ rc = VINF_SUCCESS;
+ break;
+ case 301:
+ {
+ const char *pszRedirect;
+ curl_easy_getinfo(pThis->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
+ size_t cb = strlen(pszRedirect);
+ if (cb > 0 && cb < 2048)
+ pThis->pszRedirLocation = RTStrDup(pszRedirect);
+ rc = VERR_HTTP_REDIRECTED;
+ break;
+ }
+ case 400:
+ /* bad request */
+ rc = VERR_HTTP_BAD_REQUEST;
+ break;
+ case 403:
+ /* forbidden, authorization will not help */
+ rc = VERR_HTTP_ACCESS_DENIED;
+ break;
+ case 404:
+ /* URL not found */
+ rc = VERR_HTTP_NOT_FOUND;
+ break;
+ }
+
+ if (pThis->pszRedirLocation)
+ Log(("rtHttpGetCalcStatus: rc=%Rrc lastResp=%lu redir='%s'\n", rc, pThis->lLastResp, pThis->pszRedirLocation));
+ else
+ Log(("rtHttpGetCalcStatus: rc=%Rrc lastResp=%lu\n", rc, pThis->lLastResp));
+ }
+ else
+ {
+ switch (rcCurl)
+ {
+ case CURLE_URL_MALFORMAT:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ rc = VERR_HTTP_NOT_FOUND;
+ break;
+ case CURLE_COULDNT_CONNECT:
+ rc = VERR_HTTP_COULDNT_CONNECT;
+ break;
+ case CURLE_SSL_CONNECT_ERROR:
+ rc = VERR_HTTP_SSL_CONNECT_ERROR;
+ break;
+ case CURLE_SSL_CACERT:
+ /* The peer certificate cannot be authenticated with the CA certificates
+ * set by RTHttpSetCAFile(). We need other or additional CA certificates. */
+ rc = VERR_HTTP_CACERT_CANNOT_AUTHENTICATE;
+ break;
+ case CURLE_SSL_CACERT_BADFILE:
+ /* CAcert file (see RTHttpSetCAFile()) has wrong format */
+ rc = VERR_HTTP_CACERT_WRONG_FORMAT;
+ break;
+ case CURLE_ABORTED_BY_CALLBACK:
+ /* forcefully aborted */
+ rc = VERR_HTTP_ABORTED;
+ break;
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ rc = VERR_HTTP_PROXY_NOT_FOUND;
+ break;
+ case CURLE_WRITE_ERROR:
+ rc = RT_FAILURE_NP(pThis->rcOutput) ? pThis->rcOutput : VERR_WRITE_ERROR;
+ break;
+ //case CURLE_READ_ERROR
+
+ default:
+ break;
+ }
+ Log(("rtHttpGetCalcStatus: rc=%Rrc rcCurl=%u\n", rc, rcCurl));
+ }
+
+ return rc;
+}
+
+
+/**
+ * cURL callback for reporting progress, we use it for checking for abort.
+ */
+static int rtHttpProgress(void *pData, double rdTotalDownload, double rdDownloaded, double rdTotalUpload, double rdUploaded)
+{
+ PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pData;
+ AssertReturn(pThis->u32Magic == RTHTTP_MAGIC, 1);
+
+ pThis->cbDownloadHint = (uint64_t)rdTotalDownload;
+
+ return pThis->fAbort ? 1 : 0;
+}
+
+
+/**
+ * Whether we're likely to need SSL to handle the give URL.
+ *
+ * @returns true if we need, false if we probably don't.
+ * @param pszUrl The URL.
+ */
+static bool rtHttpNeedSsl(const char *pszUrl)
+{
+ return RTStrNICmp(pszUrl, RT_STR_TUPLE("https:")) == 0;
+}
+
+
+/**
+ * Applies recoded settings to the cURL instance before doing work.
+ *
+ * @returns IPRT status code.
+ * @param pThis The HTTP/HTTPS client instance.
+ * @param pszUrl The URL.
+ */
+static int rtHttpApplySettings(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+ /*
+ * The URL.
+ */
+ int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_URL, pszUrl);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Proxy config.
+ */
+ int rc = rtHttpConfigureProxyForUrl(pThis, pszUrl);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Setup SSL. Can be a bit of work.
+ */
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_INVALID_PARAMETER;
+
+ const char *pszCaFile = pThis->pszCaFile;
+ if ( !pszCaFile
+ && rtHttpNeedSsl(pszUrl))
+ {
+ rc = RTHttpUseTemporaryCaFile(pThis, NULL);
+ if (RT_SUCCESS(rc))
+ pszCaFile = pThis->pszCaFile;
+ else
+ return rc; /* Non-portable alternative: pszCaFile = "/etc/ssl/certs/ca-certificates.crt"; */
+ }
+ if (pszCaFile)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CAINFO, pszCaFile);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_HTTP_CURL_ERROR;
+ }
+
+ /*
+ * Progress/abort.
+ */
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_HTTP_CURL_ERROR;
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSDATA, (void *)pThis);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_HTTP_CURL_ERROR;
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROGRESS, (long)0);
+ if (CURL_FAILURE(rcCurl))
+ return VERR_HTTP_CURL_ERROR;
+
+ /*
+ * Set default user agent string if necessary. Some websites take offence
+ * if we don't set it.
+ */
+ if ( !pThis->fHaveSetUserAgent
+ && !pThis->fHaveUserAgentHeader)
+ {
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_USERAGENT, "Mozilla/5.0 (AgnosticOS; Blend) IPRT/64.42");
+ if (CURL_FAILURE(rcCurl))
+ return VERR_HTTP_CURL_ERROR;
+ pThis->fHaveSetUserAgent = true;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * cURL callback for writing data.
+ */
+static size_t rtHttpWriteData(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
+{
+ PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
+
+ /*
+ * Do max size and overflow checks.
+ */
+ size_t const cbToAppend = cbUnit * cUnits;
+ size_t const cbCurSize = pThis->Output.Mem.cb;
+ size_t const cbNewSize = cbCurSize + cbToAppend;
+ if ( cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE
+ && cbNewSize < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
+ {
+ if (cbNewSize + 1 <= pThis->Output.Mem.cbAllocated)
+ {
+ memcpy(&pThis->Output.Mem.pb[cbCurSize], pvBuf, cbToAppend);
+ pThis->Output.Mem.cb = cbNewSize;
+ pThis->Output.Mem.pb[cbNewSize] = '\0';
+ return cbToAppend;
+ }
+
+ /*
+ * We need to reallocate the output buffer.
+ */
+ /** @todo this could do with a better strategy wrt growth. */
+ size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64);
+ if ( cbAlloc <= pThis->cbDownloadHint
+ && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
+ cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64);
+
+ uint8_t *pbNew = (uint8_t *)RTMemRealloc(pThis->Output.Mem.pb, cbAlloc);
+ if (pbNew)
+ {
+ memcpy(&pbNew[cbCurSize], pvBuf, cbToAppend);
+ pbNew[cbNewSize] = '\0';
+
+ pThis->Output.Mem.cbAllocated = cbAlloc;
+ pThis->Output.Mem.pb = pbNew;
+ pThis->Output.Mem.cb = cbNewSize;
+ return cbToAppend;
+ }
+
+ pThis->rcOutput = VERR_NO_MEMORY;
+ }
+ else
+ pThis->rcOutput = VERR_TOO_MUCH_DATA;
+
+ /*
+ * Failure - abort.
+ */
+ RTMemFree(pThis->Output.Mem.pb);
+ pThis->Output.Mem.pb = NULL;
+ pThis->Output.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE;
+ pThis->fAbort = true;
+ return 0;
+}
+
+
+/**
+ * Internal worker that performs a HTTP GET.
+ *
+ * @returns IPRT status code.
+ * @param hHttp The HTTP/HTTPS client instance.
+ * @param pszUrl The URL.
+ * @param ppvResponse Where to return the pointer to the allocated
+ * response data (RTMemFree). There will always be
+ * an zero terminator char after the response, that
+ * is not part of the size returned via @a pcb.
+ * @param pcb The size of the response data.
+ *
+ * @remarks We ASSUME the API user doesn't do concurrent GETs in different
+ * threads, because that will probably blow up!
+ */
+static int rtHttpGetToMem(RTHTTP hHttp, const char *pszUrl, uint8_t **ppvResponse, size_t *pcb)
+{
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ /*
+ * Reset the return values in case of more "GUI programming" on the client
+ * side (i.e. a programming style not bothering checking return codes).
+ */
+ *ppvResponse = NULL;
+ *pcb = 0;
+
+ /*
+ * Set the busy flag (paranoia).
+ */
+ bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
+ AssertReturn(!fBusy, VERR_WRONG_ORDER);
+
+ /*
+ * Reset the state and apply settings.
+ */
+ pThis->fAbort = false;
+ pThis->rcOutput = VINF_SUCCESS;
+ pThis->cbDownloadHint = 0;
+
+ int rc = rtHttpApplySettings(hHttp, pszUrl);
+ if (RT_SUCCESS(rc))
+ {
+ RT_ZERO(pThis->Output.Mem);
+ int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
+ if (!CURL_FAILURE(rcCurl))
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
+ if (!CURL_FAILURE(rcCurl))
+ {
+ /*
+ * Perform the HTTP operation.
+ */
+ rcCurl = curl_easy_perform(pThis->pCurl);
+ rc = rtHttpGetCalcStatus(pThis, rcCurl);
+ if (RT_SUCCESS(rc))
+ rc = pThis->rcOutput;
+ if (RT_SUCCESS(rc))
+ {
+ *ppvResponse = pThis->Output.Mem.pb;
+ *pcb = pThis->Output.Mem.cb;
+ Log(("rtHttpGetToMem: %zx bytes (allocated %zx)\n", pThis->Output.Mem.cb, pThis->Output.Mem.cbAllocated));
+ }
+ else if (pThis->Output.Mem.pb)
+ RTMemFree(pThis->Output.Mem.pb);
+ RT_ZERO(pThis->Output.Mem);
+ }
+ else
+ rc = VERR_HTTP_CURL_ERROR;
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
+
+RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8)
+{
+ Log(("RTHttpGetText: hHttp=%p pszUrl=%s\n", hHttp, pszUrl));
+ uint8_t *pv;
+ size_t cb;
+ int rc = rtHttpGetToMem(hHttp, pszUrl, &pv, &cb);
+ if (RT_SUCCESS(rc))
+ {
+ if (pv) /* paranoia */
+ *ppszNotUtf8 = (char *)pv;
+ else
+ *ppszNotUtf8 = (char *)RTMemDup("", 1);
+ }
+ else
+ *ppszNotUtf8 = NULL;
+ return rc;
+}
+
+
+RTR3DECL(void) RTHttpFreeResponseText(char *pszNotUtf8)
+{
+ RTMemFree(pszNotUtf8);
+}
+
+
+RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb)
+{
+ Log(("RTHttpGetBinary: hHttp=%p pszUrl=%s\n", hHttp, pszUrl));
+ return rtHttpGetToMem(hHttp, pszUrl, (uint8_t **)ppvResponse, pcb);
+}
+
+
+RTR3DECL(void) RTHttpFreeResponse(void *pvResponse)
+{
+ RTMemFree(pvResponse);
+}
+
+
+/**
+ * cURL callback for writing data to a file.
+ */
+static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
+{
+ PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
+ size_t cbWritten = 0;
+ int rc = RTFileWrite(pThis->Output.hFile, pvBuf, cbUnit * cUnits, &cbWritten);
+ if (RT_SUCCESS(rc))
+ return cbWritten;
+ Log(("rtHttpWriteDataToFile: rc=%Rrc cbUnit=%zd cUnits=%zu\n", rc, cbUnit, cUnits));
+ pThis->rcOutput = rc;
+ return 0;
+}
+
+
+RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
+{
+ Log(("RTHttpGetBinary: hHttp=%p pszUrl=%s pszDstFile=%s\n", hHttp, pszUrl, pszDstFile));
+ PRTHTTPINTERNAL pThis = hHttp;
+ RTHTTP_VALID_RETURN(pThis);
+
+ /*
+ * Set the busy flag (paranoia).
+ */
+ bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
+ AssertReturn(!fBusy, VERR_WRONG_ORDER);
+
+ /*
+ * Reset the state and apply settings.
+ */
+ pThis->fAbort = false;
+ pThis->rcOutput = VINF_SUCCESS;
+ pThis->cbDownloadHint = 0;
+
+ int rc = rtHttpApplySettings(hHttp, pszUrl);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->Output.hFile = NIL_RTFILE;
+ int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
+ if (!CURL_FAILURE(rcCurl))
+ rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
+ if (!CURL_FAILURE(rcCurl))
+ {
+ /*
+ * Open the output file.
+ */
+ rc = RTFileOpen(&pThis->Output.hFile, pszDstFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_READWRITE);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Perform the HTTP operation.
+ */
+ rcCurl = curl_easy_perform(pThis->pCurl);
+ rc = rtHttpGetCalcStatus(pThis, rcCurl);
+ if (RT_SUCCESS(rc))
+ rc = pThis->rcOutput;
+
+ int rc2 = RTFileClose(pThis->Output.hFile);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ pThis->Output.hFile = NIL_RTFILE;
+ }
+ else
+ rc = VERR_HTTP_CURL_ERROR;
+ }
+
+ ASMAtomicWriteBool(&pThis->fBusy, false);
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
index 6b89535..023ef6d 100644
--- a/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/RTLogWriteDebugger-r0drv-darwin.cpp
@@ -35,7 +35,8 @@
RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
kprintf("%.*s", (int)cb, pch);
- return;
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
index bf5e590..b1c8765 100644
--- a/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/RTLogWriteStdOut-r0drv-darwin.cpp
@@ -35,7 +35,8 @@
RTDECL(void) RTLogWriteStdOut(const char *pch, size_t cb)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
printf("%.*s", (int)cb, pch);
- return;
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/darwin/alloc-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/alloc-r0drv-darwin.cpp
index abb2752..891fdbe 100644
--- a/src/VBox/Runtime/r0drv/darwin/alloc-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/alloc-r0drv-darwin.cpp
@@ -67,6 +67,8 @@ typedef RTMEMDARWINHDREX *PRTMEMDARWINHDREX;
*/
DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
if (RT_UNLIKELY(fFlags & RTMEMHDR_FLAG_ANY_CTX))
return VERR_NOT_SUPPORTED;
@@ -76,7 +78,10 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
RTR0MEMOBJ hMemObj;
int rc = RTR0MemObjAllocPage(&hMemObj, cb + sizeof(RTMEMDARWINHDREX), true /*fExecutable*/);
if (RT_FAILURE(rc))
+ {
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
+ }
PRTMEMDARWINHDREX pExHdr = (PRTMEMDARWINHDREX)RTR0MemObjAddress(hMemObj);
pExHdr->hMemObj = hMemObj;
pHdr = &pExHdr->Hdr;
@@ -87,11 +92,11 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
}
else
{
-
pHdr = (PRTMEMHDR)IOMalloc(cb + sizeof(*pHdr));
if (RT_UNLIKELY(!pHdr))
{
printf("rtR0MemAllocEx(%#zx, %#x) failed\n", cb + sizeof(*pHdr), fFlags);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
}
@@ -100,7 +105,9 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
pHdr->fFlags = fFlags;
pHdr->cb = cb;
pHdr->cbReq = cb;
- *ppHdr = pHdr;;
+ *ppHdr = pHdr;
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -110,6 +117,8 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
*/
DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
pHdr->u32Magic += 1;
if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC)
{
@@ -119,6 +128,8 @@ DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
}
else
IOFree(pHdr, pHdr->cb + sizeof(*pHdr));
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
@@ -130,6 +141,7 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
AssertPtr(pPhys);
Assert(cb > 0);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Allocate the memory and ensure that the API is still providing
@@ -145,6 +157,7 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
if (!((uintptr_t)pv & PAGE_OFFSET_MASK))
{
*pPhys = PhysAddr;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return pv;
}
AssertMsgFailed(("IOMallocContiguous didn't return a page aligned address - %p!\n", pv));
@@ -153,6 +166,8 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
AssertMsgFailed(("IOMallocContiguous returned high address! PhysAddr=%RX64 cb=%#zx\n", (uint64_t)PhysAddr, cb));
IOFreeContiguous(pv, cb);
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return NULL;
}
@@ -164,9 +179,12 @@ RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
{
Assert(cb > 0);
AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
+ IPRT_DARWIN_SAVE_EFL_AC();
cb = RT_ALIGN_Z(cb, PAGE_SIZE);
IOFreeContiguous(pv, cb);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
}
diff --git a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
index c221df4..4aa97c1 100644
--- a/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/assert-r0drv-darwin.cpp
@@ -42,15 +42,18 @@
DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
printf("\r\n!!Assertion Failed!!\r\n"
"Expression: %s\r\n"
"Location : %s(%d) %s\r\n",
pszExpr, pszFile, uLine, pszFunction);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
char szMsg[256];
RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
@@ -58,6 +61,7 @@ DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_
printf("%s", szMsg);
NOREF(fInitial);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
index 31f1c18..5e7105f 100644
--- a/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp
@@ -215,6 +215,7 @@ RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
RTFILEINT *pThis = (RTFILEINT *)RTMemAllocZ(sizeof(*pThis));
if (!pThis)
return VERR_NO_MEMORY;
+ IPRT_DARWIN_SAVE_EFL_AC();
errno_t rc;
pThis->u32Magic = RTFILE_MAGIC;
@@ -256,6 +257,7 @@ RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
break;
default:
AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#x\n", fOpen));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_INVALID_PARAMETER;
}
@@ -264,6 +266,7 @@ RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
if (rc == 0)
{
*phFile = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -273,6 +276,7 @@ RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
rc = VERR_INTERNAL_ERROR_5;
RTMemFree(pThis);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -287,7 +291,9 @@ RTDECL(int) RTFileClose(RTFILE hFile)
AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
pThis->u32Magic = ~RTFILE_MAGIC;
+ IPRT_DARWIN_SAVE_EFL_AC();
errno_t rc = vnode_close(pThis->hVnode, pThis->fOpenMode & (FREAD | FWRITE), pThis->hVfsCtx);
+ IPRT_DARWIN_RESTORE_EFL_AC();
RTMemFree(pThis);
return RTErrConvertFromErrno(rc);
@@ -302,6 +308,7 @@ RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead,
off_t offNative = (off_t)off;
AssertReturn((RTFOFF)offNative == off, VERR_OUT_OF_RANGE);
+ IPRT_DARWIN_SAVE_EFL_AC();
#if 0 /* Added in 10.6, grr. */
errno_t rc;
@@ -315,12 +322,16 @@ RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead,
vfs_context_ucred(pThis->hVfsCtx), &cbLeft, vfs_context_proc(pThis->hVfsCtx));
*pcbRead = cbToRead - cbLeft;
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return !rc ? VINF_SUCCESS : RTErrConvertFromErrno(rc);
#else
uio_t hUio = uio_create(1, offNative, UIO_SYSSPACE, UIO_READ);
if (!hUio)
+ {
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
errno_t rc;
if (uio_addiov(hUio, (user_addr_t)(uintptr_t)pvBuf, cbToRead) == 0)
{
@@ -333,6 +344,7 @@ RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead,
else
rc = VERR_INTERNAL_ERROR_3;
uio_free(hUio);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
#endif
diff --git a/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
index 98ba22a..4b21230 100644
--- a/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/initterm-r0drv-darwin.cpp
@@ -51,6 +51,8 @@ PFNR0DARWINCPUINTERRUPT g_pfnR0DarwinCpuInterrupt = NULL;
DECLHIDDEN(int) rtR0InitNative(void)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Create the lock group.
*/
@@ -85,12 +87,15 @@ DECLHIDDEN(int) rtR0InitNative(void)
if (RT_FAILURE(rc))
rtR0TermNative();
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(void) rtR0TermNative(void)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Preemption hacks before the lock group.
*/
@@ -104,5 +109,7 @@ DECLHIDDEN(void) rtR0TermNative(void)
lck_grp_free(g_pDarwinLockGroup);
g_pDarwinLockGroup = NULL;
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
index 6faf85a..53b0fc0 100644
--- a/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
@@ -354,6 +354,7 @@ static uint64_t rtR0MemObjDarwinGetPTE(void *pvPage)
DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
{
PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)pMem;
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Release the IOMemoryDescriptor or/and IOMemoryMap associated with the object.
@@ -404,10 +405,12 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
case RTR0MEMOBJTYPE_PHYS_NC:
AssertMsgFailed(("RTR0MEMOBJTYPE_PHYS_NC\n"));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_INTERNAL_ERROR;
case RTR0MEMOBJTYPE_RES_VIRT:
AssertMsgFailed(("RTR0MEMOBJTYPE_RES_VIRT\n"));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_INTERNAL_ERROR;
case RTR0MEMOBJTYPE_MAPPING:
@@ -416,9 +419,11 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
default:
AssertMsgFailed(("enmType=%d\n", pMemDarwin->Core.enmType));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_INTERNAL_ERROR;
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -609,13 +614,20 @@ static int rtR0MemObjNativeAllocWorker(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
- return rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
- 0 /* PhysMask */, UINT64_MAX, RTR0MEMOBJTYPE_PAGE);
+ IPRT_DARWIN_SAVE_EFL_AC();
+
+ int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
+ 0 /* PhysMask */, UINT64_MAX, RTR0MEMOBJTYPE_PAGE);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Try IOMallocPhysical/IOMallocAligned first.
* Then try optimistically without a physical address mask, which will always
@@ -628,12 +640,16 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
if (rc == VERR_ADDRESS_TOO_BIG)
rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, false /* fContiguous */,
0 /* PhysMask */, _4G - PAGE_SIZE, RTR0MEMOBJTYPE_LOW);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
int rc = rtR0MemObjNativeAllocWorker(ppMem, cb, fExecutable, true /* fContiguous */,
~(uint32_t)PAGE_OFFSET_MASK, _4G - PAGE_SIZE,
RTR0MEMOBJTYPE_CONT);
@@ -646,6 +662,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
rc = rtR0MemObjNativeAllocWorker(ppMem, cb + PAGE_SIZE, fExecutable, true /* fContiguous */,
~(uint32_t)PAGE_OFFSET_MASK, _4G - PAGE_SIZE,
RTR0MEMOBJTYPE_CONT);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -656,6 +673,8 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
if (uAlignment != PAGE_SIZE)
return VERR_NOT_SUPPORTED;
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Translate the PhysHighest address into a mask.
*/
@@ -675,6 +694,8 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
rc = rtR0MemObjNativeAllocWorker(ppMem, cb, true /* fExecutable */, true /* fContiguous */,
PhysMask, PhysHighest, RTR0MEMOBJTYPE_PHYS);
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -693,6 +714,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t c
DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
{
AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE, VERR_NOT_SUPPORTED);
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Create a descriptor for it (the validation is always true on intel macs, but
@@ -724,6 +746,7 @@ DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS P
pMemDarwin->Core.u.Phys.uCachePolicy = uCachePolicy;
pMemDarwin->pMemDesc = pMemDesc;
*ppMem = &pMemDarwin->Core;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -735,6 +758,7 @@ DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS P
}
else
AssertMsgFailed(("%#llx %llx\n", (unsigned long long)Phys, (unsigned long long)cb));
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -753,6 +777,7 @@ DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS P
*/
static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess, task_t Task)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
NOREF(fAccess);
#ifdef USE_VM_MAP_WIRE
vm_map_t Map = get_task_map(Task);
@@ -777,6 +802,8 @@ static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb,
{
pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
*ppMem = &pMemDarwin->Core;
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -806,6 +833,8 @@ static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb,
pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
pMemDarwin->pMemDesc = pMemDesc;
*ppMem = &pMemDarwin->Core;
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -817,6 +846,7 @@ static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb,
pMemDesc->release();
}
#endif
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -856,6 +886,8 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
if (uAlignment > PAGE_SIZE)
return VERR_NOT_SUPPORTED;
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Must have a memory descriptor that we can map.
*/
@@ -926,6 +958,8 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
pMemDarwin->pMemMap = pMemMap;
// pMemDarwin->pMemDesc = pMemDesc;
*ppMem = &pMemDarwin->Core;
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -946,6 +980,8 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
else
rc = VERR_MAP_FAILED;
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
@@ -959,6 +995,8 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
if (uAlignment > PAGE_SIZE)
return VERR_NOT_SUPPORTED;
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/*
* Must have a memory descriptor.
*/
@@ -993,6 +1031,8 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
pMemDarwin->Core.u.Mapping.R0Process = R0Process;
pMemDarwin->pMemMap = pMemMap;
*ppMem = &pMemDarwin->Core;
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -1005,16 +1045,23 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
else
rc = VERR_MAP_FAILED;
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
/* Get the map for the object. */
vm_map_t pVmMap = rtR0MemObjDarwinGetMap(pMem);
if (!pVmMap)
+ {
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NOT_SUPPORTED;
+ }
/*
* Convert the protection.
@@ -1076,6 +1123,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub,
krc2, (void *)pvReal, (void *)cbReal, Info.protection, Info.max_protection, Info.inheritance,
Info.shared, Info.reserved, Info.offset, Info.behavior, Info.user_wired_count);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return RTErrConvertFromDarwinKern(krc);
}
@@ -1099,6 +1147,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub,
rtR0MemObjDarwinSniffPages((void const *)Start, cbSub);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -1107,6 +1156,7 @@ DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, s
{
RTHCPHYS PhysAddr;
PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)pMem;
+ IPRT_DARWIN_SAVE_EFL_AC();
#ifdef USE_VM_MAP_WIRE
/*
@@ -1149,6 +1199,7 @@ DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, s
PgNo = pmap_find_phys(Pmap, (uintptr_t)pMemDarwin->Core.pv + iPage * PAGE_SIZE);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
AssertReturn(PgNo, NIL_RTHCPHYS);
PhysAddr = (RTHCPHYS)PgNo << PAGE_SHIFT;
Assert((PhysAddr >> PAGE_SHIFT) == PgNo);
@@ -1172,6 +1223,7 @@ DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, s
#else
addr64_t Addr = pMemDesc->getPhysicalSegment64(iPage * PAGE_SIZE, NULL);
#endif
+ IPRT_DARWIN_RESTORE_EFL_AC();
AssertMsgReturn(Addr, ("iPage=%u\n", iPage), NIL_RTHCPHYS);
PhysAddr = Addr;
AssertMsgReturn(PhysAddr == Addr, ("PhysAddr=%RHp Addr=%RX64\n", PhysAddr, (uint64_t)Addr), NIL_RTHCPHYS);
diff --git a/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
index 1c16732..072b7d8 100644
--- a/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/memuserkernel-r0drv-darwin.cpp
@@ -42,7 +42,9 @@
RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb)
{
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
int rc = copyin((const user_addr_t)R3PtrSrc, pvDst, cb);
+ IPRT_DARWIN_RESTORE_EFL_AC();
if (RT_LIKELY(rc == 0))
return VINF_SUCCESS;
return VERR_ACCESS_DENIED;
@@ -52,7 +54,9 @@ RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb)
RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb)
{
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
int rc = copyout(pvSrc, R3PtrDst, cb);
+ IPRT_DARWIN_RESTORE_EFL_AC();
if (RT_LIKELY(rc == 0))
return VINF_SUCCESS;
return VERR_ACCESS_DENIED;
diff --git a/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
index 48d0e09..a4f0edc 100644
--- a/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp
@@ -48,6 +48,8 @@ static int32_t volatile g_cMaxCpus = -1;
static int rtMpDarwinInitMaxCpus(void)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
int32_t cCpus = -1;
size_t oldLen = sizeof(cCpus);
int rc = sysctlbyname("hw.ncpu", &cCpus, &oldLen, NULL, NULL);
@@ -58,6 +60,8 @@ static int rtMpDarwinInitMaxCpus(void)
}
ASMAtomicWriteS32(&g_cMaxCpus, cCpus);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return cCpus;
}
@@ -174,13 +178,16 @@ RTDECL(bool) RTMpIsCpuWorkPending(void)
static void rtmpOnAllDarwinWrapper(void *pvArg)
{
PRTMPARGS pArgs = (PRTMPARGS)pvArg;
+ IPRT_DARWIN_SAVE_EFL_AC();
pArgs->pfnWorker(cpu_number(), pArgs->pvUser1, pArgs->pvUser2);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
RTMPARGS Args;
Args.pfnWorker = pfnWorker;
@@ -189,6 +196,8 @@ RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
Args.idCpu = NIL_RTCPUID;
Args.cHits = 0;
mp_rendezvous_no_intrs(rtmpOnAllDarwinWrapper, &Args);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -204,13 +213,18 @@ static void rtmpOnOthersDarwinWrapper(void *pvArg)
PRTMPARGS pArgs = (PRTMPARGS)pvArg;
RTCPUID idCpu = cpu_number();
if (pArgs->idCpu != idCpu)
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ }
}
RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
int rc;
RTMPARGS Args;
@@ -220,6 +234,8 @@ RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
Args.idCpu = RTMpCpuId();
Args.cHits = 0;
mp_rendezvous_no_intrs(rtmpOnOthersDarwinWrapper, &Args);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -236,8 +252,10 @@ static void rtmpOnSpecificDarwinWrapper(void *pvArg)
RTCPUID idCpu = cpu_number();
if (pArgs->idCpu == idCpu)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
ASMAtomicIncU32(&pArgs->cHits);
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
}
@@ -245,6 +263,7 @@ static void rtmpOnSpecificDarwinWrapper(void *pvArg)
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
int rc;
RTMPARGS Args;
@@ -254,6 +273,8 @@ RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1
Args.idCpu = idCpu;
Args.cHits = 0;
mp_rendezvous_no_intrs(rtmpOnSpecificDarwinWrapper, &Args);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return Args.cHits == 1
? VINF_SUCCESS
: VERR_CPU_NOT_FOUND;
@@ -266,7 +287,9 @@ RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
if (g_pfnR0DarwinCpuInterrupt == NULL)
return VERR_NOT_SUPPORTED;
+ IPRT_DARWIN_SAVE_EFL_AC(); /* paranoia */
g_pfnR0DarwinCpuInterrupt(idCpu);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
index 9a216f4..af49df8 100644
--- a/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semevent-r0drv-darwin.cpp
@@ -100,6 +100,7 @@ RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKV
Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
if (pThis)
@@ -114,12 +115,14 @@ RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKV
if (pThis->pSpinlock)
{
*phEventSem = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
pThis->u32Magic = 0;
RTMemFree(pThis);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
@@ -146,8 +149,12 @@ DECLINLINE(void) rtR0SemEventDarwinRelease(PRTSEMEVENTINTERNAL pThis)
if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
{
Assert(pThis->u32Magic != RTSEMEVENT_MAGIC);
+ IPRT_DARWIN_SAVE_EFL_AC();
+
lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
RTMemFree(pThis);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
}
@@ -159,6 +166,7 @@ RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_spin_lock(pThis->pSpinlock);
@@ -176,6 +184,7 @@ RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
lck_spin_unlock(pThis->pSpinlock);
rtR0SemEventDarwinRelease(pThis);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -189,6 +198,7 @@ RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPT_CPUID_VAR();
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
rtR0SemEventDarwinRetain(pThis);
@@ -217,6 +227,7 @@ RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
rtR0SemEventDarwinRelease(pThis);
RT_ASSERT_PREEMPT_CPUID();
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -239,6 +250,7 @@ static int rtR0SemEventDarwinWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, ui
AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
+ IPRT_DARWIN_SAVE_EFL_AC();
rtR0SemEventDarwinRetain(pThis);
lck_spin_lock(pThis->pSpinlock);
@@ -367,6 +379,7 @@ static int rtR0SemEventDarwinWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, ui
lck_spin_unlock(pThis->pSpinlock);
rtR0SemEventDarwinRelease(pThis);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
index 9239860..0e7246c 100644
--- a/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp
@@ -103,6 +103,7 @@ RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t
AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
if (pThis)
@@ -116,12 +117,14 @@ RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t
if (pThis->pSpinlock)
{
*phEventMultiSem = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
pThis->u32Magic = 0;
RTMemFree(pThis);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
@@ -147,9 +150,13 @@ DECLINLINE(void) rtR0SemEventMultiDarwinRelease(PRTSEMEVENTMULTIINTERNAL pThis)
{
if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
{
+ IPRT_DARWIN_SAVE_EFL_AC();
Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
+
lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
RTMemFree(pThis);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
}
@@ -163,6 +170,7 @@ RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
Assert(pThis->cRefs > 0);
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_spin_lock(pThis->pSpinlock);
@@ -177,6 +185,7 @@ RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
lck_spin_unlock(pThis->pSpinlock);
rtR0SemEventMultiDarwinRelease(pThis);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -188,6 +197,7 @@ RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPT_CPUID_VAR();
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
rtR0SemEventMultiDarwinRetain(pThis);
lck_spin_lock(pThis->pSpinlock);
@@ -213,6 +223,7 @@ RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
rtR0SemEventMultiDarwinRelease(pThis);
RT_ASSERT_PREEMPT_CPUID();
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -224,6 +235,7 @@ RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPT_CPUID_VAR();
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
rtR0SemEventMultiDarwinRetain(pThis);
lck_spin_lock(pThis->pSpinlock);
@@ -234,6 +246,7 @@ RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
rtR0SemEventMultiDarwinRelease(pThis);
RT_ASSERT_PREEMPT_CPUID();
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -258,6 +271,7 @@ static int rtR0SemEventMultiDarwinWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t
AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
if (uTimeout != 0 || (fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
rtR0SemEventMultiDarwinRetain(pThis);
lck_spin_lock(pThis->pSpinlock);
@@ -381,6 +395,8 @@ static int rtR0SemEventMultiDarwinWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t
lck_spin_unlock(pThis->pSpinlock);
rtR0SemEventMultiDarwinRelease(pThis);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return rc;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/semfastmutex-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semfastmutex-r0drv-darwin.cpp
index 407381e..8b2fce0 100644
--- a/src/VBox/Runtime/r0drv/darwin/semfastmutex-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semfastmutex-r0drv-darwin.cpp
@@ -66,6 +66,7 @@ RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
AssertCompile(sizeof(RTSEMFASTMUTEXINTERNAL) > sizeof(void *));
AssertPtrReturn(phFastMtx, VERR_INVALID_POINTER);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
PRTSEMFASTMUTEXINTERNAL pThis = (PRTSEMFASTMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
if (pThis)
@@ -76,11 +77,13 @@ RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
if (pThis->pMtx)
{
*phFastMtx = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RTMemFree(pThis);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
@@ -93,6 +96,7 @@ RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
ASMAtomicWriteU32(&pThis->u32Magic, RTSEMFASTMUTEX_MAGIC_DEAD);
Assert(g_pDarwinLockGroup);
@@ -100,6 +104,7 @@ RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX hFastMtx)
pThis->pMtx = NULL;
RTMemFree(pThis);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -110,8 +115,11 @@ RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_mtx_lock(pThis->pMtx);
+
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
@@ -122,8 +130,11 @@ RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertMsgReturn(pThis->u32Magic == RTSEMFASTMUTEX_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_mtx_unlock(pThis->pMtx);
+
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
index ef0f9d8..fbabef5 100644
--- a/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/semmutex-r0drv-darwin.cpp
@@ -80,6 +80,7 @@ RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
{
AssertReturn(!(fFlags & ~RTSEMMUTEX_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
AssertCompile(sizeof(RTSEMMUTEXINTERNAL) > sizeof(void *));
PRTSEMMUTEXINTERNAL pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
@@ -95,11 +96,13 @@ RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
if (pThis->pSpinlock)
{
*phMutexSem = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RTMemFree(pThis);
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
@@ -109,9 +112,13 @@ RTDECL(int) RTSemMutexCreateEx(PRTSEMMUTEX phMutexSem, uint32_t fFlags,
*/
static void rtSemMutexDarwinFree(PRTSEMMUTEXINTERNAL pThis)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
lck_spin_unlock(pThis->pSpinlock);
lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
RTMemFree(pThis);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
@@ -126,6 +133,7 @@ RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
RT_ASSERT_INTS_ON();
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Kill it, wake up all waiting threads and release the reference.
@@ -141,6 +149,7 @@ RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMutexSem)
else
lck_spin_unlock(pThis->pSpinlock);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -182,6 +191,7 @@ static int rtR0SemMutexDarwinRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVA
rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
(event_t)pThis, fInterruptible, u64AbsTime);
}
+
/*
* Translate the rc.
*/
@@ -264,6 +274,7 @@ DECLINLINE(int) rtR0SemMutexDarwinRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMi
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Grab the lock and check out the state.
@@ -294,9 +305,14 @@ DECLINLINE(int) rtR0SemMutexDarwinRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMi
/* Yawn, time for a nap... */
else
- return rtR0SemMutexDarwinRequestSleep(pThis, cMillies, fInterruptible, hNativeSelf);
+ {
+ rc = rtR0SemMutexDarwinRequestSleep(pThis, cMillies, fInterruptible, hNativeSelf);
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
+ return rc;
+ }
lck_spin_unlock(pThis->pSpinlock);
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
return rc;
}
@@ -334,6 +350,7 @@ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Take the lock and do the job.
@@ -349,9 +366,7 @@ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
{
pThis->hNativeOwner = NIL_RTNATIVETHREAD;
if (pThis->cWaiters > 0)
- {
- int rc2=thread_wakeup_prim((event_t)pThis, TRUE /* one_thread */, THREAD_AWAKENED);
- }
+ thread_wakeup_prim((event_t)pThis, TRUE /* one_thread */, THREAD_AWAKENED);
}
}
@@ -361,6 +376,7 @@ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMutexSem)
lck_spin_unlock(pThis->pSpinlock);
AssertRC(rc);
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
@@ -373,6 +389,7 @@ RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
RTSEMMUTEXINTERNAL *pThis = hMutexSem;
AssertPtrReturn(pThis, false);
AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, false);
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Take the lock and do the check.
@@ -381,6 +398,7 @@ RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
bool fRc = pThis->hNativeOwner != NIL_RTNATIVETHREAD;
lck_spin_unlock(pThis->pSpinlock);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return fRc;
}
diff --git a/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
index bc744da..49e8ed1 100644
--- a/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/spinlock-r0drv-darwin.cpp
@@ -70,32 +70,35 @@ RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char
{
RT_ASSERT_PREEMPTIBLE();
AssertReturn(fFlags == RTSPINLOCK_FLAGS_INTERRUPT_SAFE || fFlags == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, VERR_INVALID_PARAMETER);
+ IPRT_DARWIN_SAVE_EFL_AC();
/*
* Allocate.
*/
AssertCompile(sizeof(RTSPINLOCKINTERNAL) > sizeof(void *));
PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)RTMemAlloc(sizeof(*pThis));
- if (!pThis)
- return VERR_NO_MEMORY;
-
- /*
- * Initialize & return.
- */
- pThis->u32Magic = RTSPINLOCK_MAGIC;
- pThis->fIntSaved = 0;
- pThis->fFlags = fFlags;
- pThis->pszName = pszName;
- Assert(g_pDarwinLockGroup);
- pThis->pSpinLock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
- if (!pThis->pSpinLock)
+ if (pThis)
{
+ /*
+ * Initialize & return.
+ */
+ pThis->u32Magic = RTSPINLOCK_MAGIC;
+ pThis->fIntSaved = 0;
+ pThis->fFlags = fFlags;
+ pThis->pszName = pszName;
+ Assert(g_pDarwinLockGroup);
+ pThis->pSpinLock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
+ if (pThis->pSpinLock)
+ {
+ *pSpinlock = pThis;
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+
RTMemFree(pThis);
- return VERR_NO_MEMORY;
}
-
- *pSpinlock = pThis;
- return VINF_SUCCESS;
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ return VERR_NO_MEMORY;
}
@@ -115,12 +118,15 @@ RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
* Make the lock invalid and release the memory.
*/
ASMAtomicIncU32(&pThis->u32Magic);
+ IPRT_DARWIN_SAVE_EFL_AC();
Assert(g_pDarwinLockGroup);
- lck_spin_destroy(pThis->pSpinLock, g_pDarwinLockGroup);
+ lck_spin_free(pThis->pSpinLock, g_pDarwinLockGroup);
pThis->pSpinLock = NULL;
RTMemFree(pThis);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -137,9 +143,14 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
ASMIntDisable();
lck_spin_lock(pThis->pSpinLock);
pThis->fIntSaved = fIntSaved;
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC_EX(fIntSaved);
}
else
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_spin_lock(pThis->pSpinLock);
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
+ }
}
@@ -157,7 +168,11 @@ RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
ASMSetFlags(fIntSaved);
}
else
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_spin_unlock(pThis->pSpinLock);
+ IPRT_DARWIN_RESTORE_EFL_ONLY_AC();
+ }
}
diff --git a/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h b/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
index d8be50d..1754afa 100644
--- a/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
+++ b/src/VBox/Runtime/r0drv/darwin/the-darwin-kernel.h
@@ -27,7 +27,7 @@
#ifndef ___the_darwin_kernel_h
#define ___the_darwin_kernel_h
-/* Problematic header(s) containing conflicts with IPRT first. */
+/* Problematic header(s) containing conflicts with IPRT first. (FreeBSD has fixed these ages ago.) */
#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#include <sys/param.h>
@@ -37,6 +37,8 @@
#undef MAX
#undef PAGE_SIZE
#undef PAGE_SHIFT
+#undef PVM
+
/* Include the IPRT definitions of the conflicting #defines & typedefs. */
#include <iprt/cdefs.h>
@@ -72,7 +74,7 @@
#include <sys/vnode.h>
#include <sys/fcntl.h>
#include <IOKit/IOTypes.h>
-#include <IOKit/IOLib.h>
+#include <IOKit/IOLib.h> /* Note! Has Assert down as a function. */
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOMapper.h>
@@ -91,6 +93,17 @@
# define kIOMemoryMapperNone UINT32_C(0x800)
#endif
+/** @name Macros for preserving EFLAGS.AC (despair / paranoid)
+ * @remarks Unlike linux, we have to restore it unconditionally on darwin.
+ * @{ */
+#include <iprt/asm-amd64-x86.h>
+#include <iprt/x86.h>
+#define IPRT_DARWIN_SAVE_EFL_AC() RTCCUINTREG const fSavedEfl = ASMGetFlags();
+#define IPRT_DARWIN_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
+#define IPRT_DARWIN_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~X86_EFL_AC, fSavedEfl & X86_EFL_AC)
+#define IPRT_DARWIN_RESTORE_EFL_ONLY_AC_EX(a_fSavedEfl) ASMChangeFlags(~X86_EFL_AC, (a_fSavedEfl) & X86_EFL_AC)
+/** @} */
+
RT_C_DECLS_BEGIN
diff --git a/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
index 0bce605..5f6e38d 100644
--- a/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/thread-r0drv-darwin.cpp
@@ -46,9 +46,13 @@ RTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
static int rtR0ThreadDarwinSleepCommon(RTMSINTERVAL cMillies)
{
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
+
uint64_t u64Deadline;
clock_interval_to_deadline(cMillies, kMillisecondScale, &u64Deadline);
clock_delay_until(u64Deadline);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -68,7 +72,11 @@ RTDECL(int) RTThreadSleepNoLog(RTMSINTERVAL cMillies)
RTDECL(bool) RTThreadYield(void)
{
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
+
thread_block(THREAD_CONTINUE_NULL);
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
return true; /* this is fishy */
}
diff --git a/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
index 139c015..dc177b4 100644
--- a/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/thread2-r0drv-darwin.cpp
@@ -165,6 +165,7 @@ static void rtThreadNativeMain(void *pvArg, wait_result_t Ignored)
DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread)
{
RT_ASSERT_PREEMPTIBLE();
+ IPRT_DARWIN_SAVE_EFL_AC();
thread_t NativeThread;
kern_return_t kr = kernel_thread_start(rtThreadNativeMain, pThreadInt, &NativeThread);
@@ -172,8 +173,10 @@ DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pN
{
*pNativeThread = (RTNATIVETHREAD)NativeThread;
thread_deallocate(NativeThread);
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return RTErrConvertFromMachKernReturn(kr);
}
diff --git a/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp b/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
index babac23..4c7685d 100644
--- a/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
+++ b/src/VBox/Runtime/r0drv/darwin/threadpreempt-r0drv-darwin.cpp
@@ -68,6 +68,7 @@ static RTDARWINPREEMPTHACK g_aPreemptHacks[RTCPUSET_MAX_CPUS];
int rtThreadPreemptDarwinInit(void)
{
Assert(g_pDarwinLockGroup);
+ IPRT_DARWIN_SAVE_EFL_AC();
for (size_t i = 0; i < RT_ELEMENTS(g_aPreemptHacks); i++)
{
@@ -75,6 +76,7 @@ int rtThreadPreemptDarwinInit(void)
if (!g_aPreemptHacks[i].pSpinLock)
return VERR_NO_MEMORY; /* (The caller will invoke rtThreadPreemptDarwinTerm) */
}
+ IPRT_DARWIN_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -86,12 +88,16 @@ int rtThreadPreemptDarwinInit(void)
*/
void rtThreadPreemptDarwinTerm(void)
{
+ IPRT_DARWIN_SAVE_EFL_AC();
+
for (size_t i = 0; i < RT_ELEMENTS(g_aPreemptHacks); i++)
if (g_aPreemptHacks[i].pSpinLock)
{
lck_spin_free(g_aPreemptHacks[i].pSpinLock, g_pDarwinLockGroup);
g_aPreemptHacks[i].pSpinLock = NULL;
}
+
+ IPRT_DARWIN_RESTORE_EFL_AC();
}
@@ -173,7 +179,11 @@ RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
{
lck_spin_t *pSpinLock = g_aPreemptHacks[idCpu].pSpinLock;
if (pSpinLock)
+ {
+ IPRT_DARWIN_SAVE_EFL_AC();
lck_spin_unlock(pSpinLock);
+ IPRT_DARWIN_RESTORE_EFL_AC();
+ }
else
AssertFailed();
}
diff --git a/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp b/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
index ba352a6..3df4d92 100644
--- a/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
+++ b/src/VBox/Runtime/r0drv/generic/RTMpOn-r0drv-generic.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -44,6 +44,13 @@ RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
RT_EXPORT_SYMBOL(RTMpOnAll);
+RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
+{
+ return false;
+}
+RT_EXPORT_SYMBOL(RTMpOnAllIsConcurrentSafe);
+
+
RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
NOREF(pfnWorker);
@@ -64,3 +71,23 @@ RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1
}
RT_EXPORT_SYMBOL(RTMpOnSpecific);
+
+RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
+{
+ NOREF(idCpu1);
+ NOREF(idCpu2);
+ NOREF(pfnWorker);
+ NOREF(pvUser1);
+ NOREF(pvUser2);
+ return VERR_NOT_SUPPORTED;
+}
+RT_EXPORT_SYMBOL(RTMpOnPair);
+
+
+
+RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void)
+{
+ return false;
+}
+RT_EXPORT_SYMBOL(RTMpOnPairIsConcurrentExecSupported);
+
diff --git a/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
index c34f854..572d43a 100644
--- a/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c
@@ -35,7 +35,9 @@
RTDECL(void) RTLogWriteDebugger(const char *pch, size_t cb)
{
+ IPRT_LINUX_SAVE_EFL_AC();
printk("%.*s", (int)cb, pch);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
RT_EXPORT_SYMBOL(RTLogWriteDebugger);
diff --git a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
index 7c6064a..db3c768 100644
--- a/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c
@@ -227,6 +227,7 @@ static PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
{
PRTMEMHDR pHdr;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Allocate.
@@ -290,7 +291,10 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
pHdr = vmalloc(cb + sizeof(*pHdr));
}
if (RT_UNLIKELY(!pHdr))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
/*
* Initialize.
@@ -301,6 +305,7 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
pHdr->cbReq = cb;
*ppHdr = pHdr;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -310,6 +315,8 @@ DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
*/
DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
pHdr->u32Magic += 1;
if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
kfree(pHdr);
@@ -338,6 +345,8 @@ DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
#endif
else
vfree(pHdr);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
}
@@ -376,6 +385,8 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
int cOrder;
unsigned cPages;
struct page *paPages;
+ void *pvRet;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* validate input.
@@ -427,10 +438,13 @@ RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
#endif
}
*pPhys = page_to_phys(paPages);
- return phys_to_virt(page_to_phys(paPages));
+ pvRet = phys_to_virt(page_to_phys(paPages));
}
+ else
+ pvRet = NULL;
- return NULL;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return pvRet;
}
RT_EXPORT_SYMBOL(RTMemContAlloc);
@@ -449,6 +463,7 @@ RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
unsigned cPages;
unsigned iPage;
struct page *paPages;
+ IPRT_LINUX_SAVE_EFL_AC();
/* validate */
AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
@@ -471,6 +486,7 @@ RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
#endif
}
__free_pages(paPages, cOrder);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
}
RT_EXPORT_SYMBOL(RTMemContFree);
diff --git a/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
index 11b3a27..4d8c945 100644
--- a/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c
@@ -42,23 +42,27 @@
DECLHIDDEN(void) rtR0AssertNativeMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
{
+ IPRT_LINUX_SAVE_EFL_AC();
printk(KERN_EMERG
"\r\n!!Assertion Failed!!\r\n"
"Expression: %s\r\n"
"Location : %s(%d) %s\r\n",
pszExpr, pszFile, uLine, pszFunction);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
DECLHIDDEN(void) rtR0AssertNativeMsg2V(bool fInitial, const char *pszFormat, va_list va)
{
char szMsg[256];
+ IPRT_LINUX_SAVE_EFL_AC();
RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
szMsg[sizeof(szMsg) - 1] = '\0';
printk(KERN_EMERG "%s", szMsg);
NOREF(fInitial);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
index fda6e35..9894587 100644
--- a/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c
@@ -64,6 +64,8 @@ DECLHIDDEN(void) rtR0MemExecCleanup(void);
*/
DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWorker)(RTR0LNXWORKQUEUEITEM *))
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
INIT_WORK(pWork, pfnWorker);
@@ -75,6 +77,8 @@ DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWor
INIT_TQUEUE(pWork, (void (*)(void *))pfnWorker, pWork);
queue_task(pWork, &g_rtR0LnxWorkQueue);
#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
}
@@ -86,28 +90,38 @@ DECLHIDDEN(void) rtR0LnxWorkqueuePush(RTR0LNXWORKQUEUEITEM *pWork, void (*pfnWor
*/
DECLHIDDEN(void) rtR0LnxWorkqueueFlush(void)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
flush_workqueue(g_prtR0LnxWorkQueue);
#else
run_task_queue(&g_rtR0LnxWorkQueue);
#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
}
DECLHIDDEN(int) rtR0InitNative(void)
{
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
g_prtR0LnxWorkQueue = create_workqueue("iprt");
if (!g_prtR0LnxWorkQueue)
- return VERR_NO_MEMORY;
+ rc = VERR_NO_MEMORY;
#endif
- return VINF_SUCCESS;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
}
DECLHIDDEN(void) rtR0TermNative(void)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
rtR0LnxWorkqueueFlush();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 41)
destroy_workqueue(g_prtR0LnxWorkQueue);
@@ -117,5 +131,7 @@ DECLHIDDEN(void) rtR0TermNative(void)
#if defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
rtR0MemExecCleanup();
#endif
+
+ IPRT_LINUX_RESTORE_EFL_AC();
}
diff --git a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
index fd35307..bc245c1 100644
--- a/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c
@@ -1,4 +1,4 @@
-/* $Revision: 94832 $ */
+/* $Revision: 103354 $ */
/** @file
* IPRT - Ring-0 Memory Objects, Linux.
*/
@@ -547,6 +547,7 @@ static void rtR0MemObjLinuxVUnmap(PRTR0MEMOBJLNX pMemLnx)
DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)pMem;
/*
@@ -625,12 +626,14 @@ DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
AssertMsgFailed(("enmType=%d\n", pMemLnx->Core.enmType));
return VERR_INTERNAL_ERROR;
}
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTR0MEMOBJLNX pMemLnx;
int rc;
@@ -647,6 +650,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
if (RT_SUCCESS(rc))
{
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -654,12 +658,14 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
rtR0MemObjDelete(&pMemLnx->Core);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTR0MEMOBJLNX pMemLnx;
int rc;
@@ -687,6 +693,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
if (RT_SUCCESS(rc))
{
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -694,12 +701,14 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
rtR0MemObjDelete(&pMemLnx->Core);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTR0MEMOBJLNX pMemLnx;
int rc;
@@ -730,6 +739,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
#endif
pMemLnx->Core.u.Cont.Phys = page_to_phys(pMemLnx->apPages[0]);
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -737,6 +747,7 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb,
rtR0MemObjDelete(&pMemLnx->Core);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -808,6 +819,7 @@ static int rtR0MemObjLinuxAllocPhysSub(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYP
size_t cb, size_t uAlignment, RTHCPHYS PhysHighest)
{
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* There are two clear cases and that's the <=16MB and anything-goes ones.
@@ -843,6 +855,7 @@ static int rtR0MemObjLinuxAllocPhysSub(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYP
/* ZONE_DMA: 0-16MB */
rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, uAlignment, PhysHighest, GFP_DMA);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -953,6 +966,8 @@ DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t c
DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* All we need to do here is to validate that we can use
* ioremap on the specified address (32/64-bit dma_addr_t).
@@ -963,19 +978,24 @@ DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS P
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_PHYS, NULL, cb);
if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
pMemLnx->Core.u.Phys.PhysBase = PhysAddr;
pMemLnx->Core.u.Phys.fAllocated = false;
pMemLnx->Core.u.Phys.uCachePolicy = uCachePolicy;
Assert(!pMemLnx->cPages);
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
{
+ IPRT_LINUX_SAVE_EFL_AC();
const int cPages = cb >> PAGE_SHIFT;
struct task_struct *pTask = rtR0ProcessToLinuxTask(R0Process);
struct vm_area_struct **papVMAs;
@@ -996,7 +1016,10 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
*/
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, (void *)R3Ptr, cb);
if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
papVMAs = (struct vm_area_struct **)RTMemAlloc(sizeof(*papVMAs) * cPages);
if (papVMAs)
@@ -1047,6 +1070,7 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
Assert(!pMemLnx->fMappedToRing0);
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -1067,12 +1091,14 @@ DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3P
}
rtR0MemObjDelete(&pMemLnx->Core);
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
{
+ IPRT_LINUX_SAVE_EFL_AC();
void *pvLast = (uint8_t *)pv + cb - 1;
size_t const cPages = cb >> PAGE_SHIFT;
PRTR0MEMOBJLNX pMemLnx;
@@ -1105,7 +1131,10 @@ DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv,
*/
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, pv, cb);
if (!pMemLnx)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
/*
* Gather the pages.
@@ -1146,10 +1175,12 @@ DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv,
Assert(!pMemLnx->fMappedToRing0);
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
rtR0MemObjDelete(&pMemLnx->Core);
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -1157,6 +1188,7 @@ DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv,
DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
+ IPRT_LINUX_SAVE_EFL_AC();
const size_t cPages = cb >> PAGE_SHIFT;
struct page *pDummyPage;
struct page **papPages;
@@ -1171,36 +1203,39 @@ DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *
* the dummy page is mapped all over the reserved area.
*/
pDummyPage = alloc_page(GFP_HIGHUSER | __GFP_NOWARN);
- if (!pDummyPage)
- return VERR_NO_MEMORY;
- papPages = RTMemAlloc(sizeof(*papPages) * cPages);
- if (papPages)
+ if (pDummyPage)
{
- void *pv;
- size_t iPage = cPages;
- while (iPage-- > 0)
- papPages[iPage] = pDummyPage;
+ papPages = RTMemAlloc(sizeof(*papPages) * cPages);
+ if (papPages)
+ {
+ void *pv;
+ size_t iPage = cPages;
+ while (iPage-- > 0)
+ papPages[iPage] = pDummyPage;
# ifdef VM_MAP
- pv = vmap(papPages, cPages, VM_MAP, PAGE_KERNEL_RO);
+ pv = vmap(papPages, cPages, VM_MAP, PAGE_KERNEL_RO);
# else
- pv = vmap(papPages, cPages, VM_ALLOC, PAGE_KERNEL_RO);
+ pv = vmap(papPages, cPages, VM_ALLOC, PAGE_KERNEL_RO);
# endif
- RTMemFree(papPages);
- if (pv)
- {
- PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
- if (pMemLnx)
+ RTMemFree(papPages);
+ if (pv)
{
- pMemLnx->Core.u.ResVirt.R0Process = NIL_RTR0PROCESS;
- pMemLnx->cPages = 1;
- pMemLnx->apPages[0] = pDummyPage;
- *ppMem = &pMemLnx->Core;
- return VINF_SUCCESS;
+ PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
+ if (pMemLnx)
+ {
+ pMemLnx->Core.u.ResVirt.R0Process = NIL_RTR0PROCESS;
+ pMemLnx->cPages = 1;
+ pMemLnx->apPages[0] = pDummyPage;
+ *ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ vunmap(pv);
}
- vunmap(pv);
}
+ __free_page(pDummyPage);
}
- __free_page(pDummyPage);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
#else /* < 2.4.22 */
@@ -1215,6 +1250,7 @@ DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *
DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTR0MEMOBJLNX pMemLnx;
void *pv;
struct task_struct *pTask = rtR0ProcessToLinuxTask(R0Process);
@@ -1232,17 +1268,22 @@ DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR
*/
pv = rtR0MemObjLinuxDoMmap(R3PtrFixed, cb, uAlignment, pTask, RTMEM_PROT_NONE);
if (pv == (void *)-1)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
if (!pMemLnx)
{
rtR0MemObjLinuxDoMunmap(pv, cb, pTask);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
pMemLnx->Core.u.ResVirt.R0Process = R0Process;
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -1254,6 +1295,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
int rc = VERR_NO_MEMORY;
PRTR0MEMOBJLNX pMemLnxToMap = (PRTR0MEMOBJLNX)pMemToMap;
PRTR0MEMOBJLNX pMemLnx;
+ IPRT_LINUX_SAVE_EFL_AC();
/* Fail if requested to do something we can't. */
AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
@@ -1325,11 +1367,13 @@ DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ
{
pMemLnx->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
rtR0MemObjDelete(&pMemLnx->Core);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
@@ -1394,6 +1438,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
struct page *pDummyPage;
RTHCPHYS DummyPhys;
#endif
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Check for restrictions.
@@ -1409,7 +1454,10 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
*/
pDummyPage = alloc_page(GFP_USER | __GFP_NOWARN);
if (!pDummyPage)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
SetPageReserved(pDummyPage);
DummyPhys = page_to_phys(pDummyPage);
#endif
@@ -1563,6 +1611,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
pMemLnx->Core.pv = pv;
pMemLnx->Core.u.Mapping.R0Process = R0Process;
*ppMem = &pMemLnx->Core;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
@@ -1577,6 +1626,7 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
__free_page(pDummyPage);
#endif
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
diff --git a/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
index 2b78d7d..055dfab 100644
--- a/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c
@@ -37,8 +37,13 @@
RTR0DECL(int) RTR0MemUserCopyFrom(void *pvDst, RTR3PTR R3PtrSrc, size_t cb)
{
+ IPRT_LINUX_SAVE_EFL_AC();
if (RT_LIKELY(copy_from_user(pvDst, (void *)R3PtrSrc, cb) == 0))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_ACCESS_DENIED;
}
RT_EXPORT_SYMBOL(RTR0MemUserCopyFrom);
@@ -46,8 +51,13 @@ RT_EXPORT_SYMBOL(RTR0MemUserCopyFrom);
RTR0DECL(int) RTR0MemUserCopyTo(RTR3PTR R3PtrDst, void const *pvSrc, size_t cb)
{
+ IPRT_LINUX_SAVE_EFL_AC();
if (RT_LIKELY(copy_to_user((void *)R3PtrDst, pvSrc, cb) == 0))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_ACCESS_DENIED;
}
RT_EXPORT_SYMBOL(RTR0MemUserCopyTo);
@@ -55,7 +65,10 @@ RT_EXPORT_SYMBOL(RTR0MemUserCopyTo);
RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr)
{
- return access_ok(VERIFY_READ, (void *)R3Ptr, 1);
+ IPRT_LINUX_SAVE_EFL_AC();
+ bool fRc = access_ok(VERIFY_READ, (void *)R3Ptr, 1);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return fRc;
}
RT_EXPORT_SYMBOL(RTR0MemUserIsValidAddr);
@@ -113,6 +126,7 @@ static int rtR0MemKernelCopyLnxWorker(void *pvDst, void const *pvSrc, size_t cb)
# endif
# endif /* !_ASM_EXTABLE */
int rc;
+ IPRT_LINUX_SAVE_EFL_AC(); /* paranoia */
if (!cb)
return VINF_SUCCESS;
@@ -135,6 +149,7 @@ static int rtR0MemKernelCopyLnxWorker(void *pvDst, void const *pvSrc, size_t cb)
"2" (pvSrc),
"3" (cb)
: "memory");
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
#else
return VERR_NOT_SUPPORTED;
diff --git a/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
index 88971ac..0990703 100644
--- a/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c
@@ -200,6 +200,7 @@ static void rtmpLinuxWrapper(void *pvInfo)
RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
+ IPRT_LINUX_SAVE_EFL_AC();
int rc;
RTMPARGS Args;
@@ -225,6 +226,8 @@ RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
RTThreadPreemptRestore(&PreemptState);
#endif /* older kernels */
Assert(rc == 0); NOREF(rc);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTMpOnAll);
@@ -232,6 +235,7 @@ RT_EXPORT_SYMBOL(RTMpOnAll);
RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
+ IPRT_LINUX_SAVE_EFL_AC();
int rc;
RTMPARGS Args;
@@ -251,6 +255,7 @@ RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
RTThreadPreemptRestore(&PreemptState);
Assert(rc == 0); NOREF(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTMpOnOthers);
@@ -279,6 +284,7 @@ static void rtmpOnSpecificLinuxWrapper(void *pvInfo)
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
+ IPRT_LINUX_SAVE_EFL_AC();
int rc;
RTMPARGS Args;
@@ -318,6 +324,7 @@ RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1
RTThreadPreemptRestore(&PreemptState);;
NOREF(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
RT_EXPORT_SYMBOL(RTMpOnSpecific);
@@ -340,6 +347,7 @@ RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
if (!RTMpIsCpuPossible(idCpu))
return VERR_CPU_NOT_FOUND;
@@ -355,6 +363,7 @@ RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
# endif /* older kernels */
NOREF(rc);
Assert(rc == 0);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
#else /* older kernels */
diff --git a/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
index 687f3bb..85de0ce 100644
--- a/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c
@@ -199,12 +199,14 @@ static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock,
DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
{
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
# ifdef CPU_DOWN_FAILED
RTCpuSetEmpty(&g_MpPendingOfflineSet);
# endif
rc = register_cpu_notifier(&g_NotifierBlock);
+ IPRT_LINUX_RESTORE_EFL_AC();
AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc));
return VINF_SUCCESS;
}
@@ -212,7 +214,9 @@ DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
{
+ IPRT_LINUX_SAVE_EFL_AC();
unregister_cpu_notifier(&g_NotifierBlock);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
#else /* Not supported / Not needed */
diff --git a/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
index 9c4c131..3e75539 100644
--- a/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c
@@ -72,6 +72,7 @@ RTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
{
PRTSEMEVENTINTERNAL pThis;
+ IPRT_LINUX_SAVE_EFL_AC();
AssertReturn(!(fFlags & ~(RTSEMEVENT_FLAGS_NO_LOCK_VAL | RTSEMEVENT_FLAGS_BOOTSTRAP_HACK)), VERR_INVALID_PARAMETER);
Assert(!(fFlags & RTSEMEVENT_FLAGS_BOOTSTRAP_HACK) || (fFlags & RTSEMEVENT_FLAGS_NO_LOCK_VAL));
@@ -86,6 +87,7 @@ RTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKV
init_waitqueue_head(&pThis->Head);
*phEventSem = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventCreate);
@@ -117,6 +119,8 @@ DECLINLINE(void) rtR0SemEventLnxRelease(PRTSEMEVENTINTERNAL pThis)
RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate input.
*/
@@ -134,6 +138,8 @@ RTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
Assert(!waitqueue_active(&pThis->Head));
wake_up_all(&pThis->Head);
rtR0SemEventLnxRelease(pThis);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventDestroy);
@@ -141,6 +147,8 @@ RT_EXPORT_SYMBOL(RTSemEventDestroy);
RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate input.
*/
@@ -156,6 +164,7 @@ RTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
wake_up(&pThis->Head);
rtR0SemEventLnxRelease(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventSignal);
@@ -194,6 +203,7 @@ static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint6
/*
* We have to wait.
*/
+ IPRT_LINUX_SAVE_EFL_AC();
RTR0SEMLNXWAIT Wait;
rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
if (RT_SUCCESS(rc))
@@ -230,6 +240,7 @@ static int rtR0SemEventLnxWait(PRTSEMEVENTINTERNAL pThis, uint32_t fFlags, uint6
rtR0SemLnxWaitDelete(&Wait);
IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
}
rtR0SemEventLnxRelease(pThis);
diff --git a/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
index 702e1d0..c505803 100644
--- a/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c
@@ -95,6 +95,7 @@ RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t
const char *pszNameFmt, ...)
{
PRTSEMEVENTMULTIINTERNAL pThis;
+ IPRT_LINUX_SAVE_EFL_AC();
AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
@@ -106,8 +107,10 @@ RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t
init_waitqueue_head(&pThis->Head);
*phEventMultiSem = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
}
RT_EXPORT_SYMBOL(RTSemEventMultiCreate);
@@ -143,6 +146,8 @@ DECLINLINE(void) rtR0SemEventMultiLnxRelease(PRTSEMEVENTMULTIINTERNAL pThis)
RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate input.
*/
@@ -161,6 +166,8 @@ RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
Assert(!waitqueue_active(&pThis->Head));
wake_up_all(&pThis->Head);
rtR0SemEventMultiLnxRelease(pThis);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
@@ -168,6 +175,7 @@ RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
{
+ IPRT_LINUX_SAVE_EFL_AC();
uint32_t fNew;
uint32_t fOld;
@@ -197,6 +205,7 @@ RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
wake_up_all(&pThis->Head);
rtR0SemEventMultiLnxRelease(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
@@ -260,6 +269,7 @@ static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFl
* We have to wait.
*/
RTR0SEMLNXWAIT Wait;
+ IPRT_LINUX_SAVE_EFL_AC();
rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
if (RT_SUCCESS(rc))
{
@@ -295,6 +305,7 @@ static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFl
rtR0SemLnxWaitDelete(&Wait);
IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
}
rtR0SemEventMultiLnxRelease(pThis);
diff --git a/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c
index 58e2539..95185ce 100644
--- a/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c
@@ -63,6 +63,8 @@ typedef struct RTSEMFASTMUTEXINTERNAL
RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Allocate.
*/
@@ -81,6 +83,7 @@ RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX phFastMtx)
#endif
*phFastMtx = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemFastMutexCreate);
@@ -106,6 +109,8 @@ RT_EXPORT_SYMBOL(RTSemFastMutexDestroy);
RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate.
*/
@@ -120,6 +125,8 @@ RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX hFastMtx)
AssertRelease(pThis->Owner == NIL_RTNATIVETHREAD);
ASMAtomicUoWriteSize(&pThis->Owner, RTThreadNativeSelf());
#endif
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemFastMutexRequest);
@@ -127,6 +134,8 @@ RT_EXPORT_SYMBOL(RTSemFastMutexRequest);
RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate.
*/
@@ -140,6 +149,8 @@ RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX hFastMtx)
#endif
up(&pThis->Semaphore);
IPRT_DEBUG_SEMS_STATE(pThis, 'u');
+
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemFastMutexRelease);
diff --git a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
index 25f0765..7a2903a 100644
--- a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
@@ -86,26 +86,33 @@ typedef struct RTSEMMUTEXINTERNAL
RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX phMtx)
{
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Allocate.
*/
PRTSEMMUTEXINTERNAL pThis;
pThis = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pThis));
- if (!pThis)
- return VERR_NO_MEMORY;
+ if (pThis)
+ {
+ /*
+ * Initialize.
+ */
+ pThis->u32Magic = RTSEMMUTEX_MAGIC;
+ pThis->cRecursions = 0;
+ pThis->pOwnerTask = NULL;
+ pThis->cRefs = 1;
+ RTListInit(&pThis->WaiterList);
+ spin_lock_init(&pThis->Spinlock);
+
+ *phMtx = pThis;
+ }
+ else
+ rc = VERR_NO_MEMORY;
- /*
- * Initialize.
- */
- pThis->u32Magic = RTSEMMUTEX_MAGIC;
- pThis->cRecursions = 0;
- pThis->pOwnerTask = NULL;
- pThis->cRefs = 1;
- RTListInit(&pThis->WaiterList);
- spin_lock_init(&pThis->Spinlock);
-
- *phMtx = pThis;
- return VINF_SUCCESS;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
}
RT_EXPORT_SYMBOL(RTSemMutexCreate);
@@ -129,6 +136,8 @@ RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
*/
AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD, RTSEMMUTEX_MAGIC), VERR_INVALID_HANDLE);
+ IPRT_LINUX_SAVE_EFL_AC();
+
spin_lock_irqsave(&pThis->Spinlock, fSavedIrq);
RTListForEach(&pThis->WaiterList, pCur, RTSEMMUTEXLNXWAITER, ListEntry)
{
@@ -144,6 +153,8 @@ RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX hMtx)
RTMemFree(pThis);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
+
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSemMutexDestroy);
@@ -250,6 +261,7 @@ DECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMilli
struct task_struct *pSelf = current;
unsigned long fSavedIrq;
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate.
@@ -289,10 +301,15 @@ DECLINLINE(int) rtSemMutexLinuxRequest(RTSEMMUTEX hMutexSem, RTMSINTERVAL cMilli
* No, so go to sleep.
*/
else
- return rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
+ {
+ rc = rtSemMutexLinuxRequestSleep(pThis, cMillies, fInterruptible, fSavedIrq);
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
+ return rc;
+ }
IPRT_DEBUG_SEMS_STATE_RC(pThis, 'M', rc);
spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
return rc;
}
@@ -331,6 +348,7 @@ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
struct task_struct *pSelf = current;
unsigned long fSavedIrq;
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate.
@@ -366,6 +384,7 @@ RTDECL(int) RTSemMutexRelease(RTSEMMUTEX hMtx)
spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
AssertRC(rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
RT_EXPORT_SYMBOL(RTSemMutexRelease);
@@ -376,6 +395,7 @@ RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
PRTSEMMUTEXINTERNAL pThis = hMutexSem;
unsigned long fSavedIrq;
bool fOwned;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate.
@@ -391,6 +411,7 @@ RTDECL(bool) RTSemMutexIsOwned(RTSEMMUTEX hMutexSem)
fOwned = pThis->pOwnerTask != NULL;
spin_unlock_irqrestore(&pThis->Spinlock, fSavedIrq);
+ IPRT_LINUX_RESTORE_EFL_AC();
return fOwned;
}
diff --git a/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
index eb141e8..0d48a05 100644
--- a/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c
@@ -73,6 +73,7 @@ typedef struct RTSPINLOCKINTERNAL
RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName)
{
+ IPRT_LINUX_SAVE_EFL_AC();
PRTSPINLOCKINTERNAL pThis;
AssertReturn(fFlags == RTSPINLOCK_FLAGS_INTERRUPT_SAFE || fFlags == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, VERR_INVALID_PARAMETER);
@@ -97,6 +98,7 @@ RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char
spin_lock_init(&pThis->Spinlock);
*pSpinlock = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTSpinlockCreate);
@@ -126,6 +128,7 @@ RT_EXPORT_SYMBOL(RTSpinlockDestroy);
RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
{
PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ IPRT_LINUX_SAVE_EFL_AC();
RT_ASSERT_PREEMPT_CPUID_VAR();
AssertMsg(pThis && pThis->u32Magic == RTSPINLOCK_MAGIC,
("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
@@ -145,6 +148,7 @@ RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
lockdep_on();
#endif
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
}
RT_EXPORT_SYMBOL(RTSpinlockAcquire);
@@ -153,6 +157,7 @@ RT_EXPORT_SYMBOL(RTSpinlockAcquire);
RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
{
PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
+ IPRT_LINUX_SAVE_EFL_AC(); /* spin_unlock* may preempt and trash eflags.ac. */
RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS();
AssertMsg(pThis && pThis->u32Magic == RTSPINLOCK_MAGIC,
("pThis=%p u32Magic=%08x\n", pThis, pThis ? (int)pThis->u32Magic : 0));
@@ -173,6 +178,7 @@ RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
lockdep_on();
#endif
+ IPRT_LINUX_RESTORE_EFL_ONLY_AC();
RT_ASSERT_PREEMPT_CPUID();
}
RT_EXPORT_SYMBOL(RTSpinlockRelease);
diff --git a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
index 5a8d162..b270971 100644
--- a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
+++ b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
@@ -382,12 +382,12 @@ DECLINLINE(unsigned long) msecs_to_jiffies(unsigned int cMillies)
* The AMD 64 switch_to in macro in arch/x86/include/asm/switch_to.h stopped
* restoring flags.
* @{ */
-#ifdef CONFIG_X86_SMAP
+#if defined(CONFIG_X86_SMAP) || defined(RT_STRICT) || defined(IPRT_WITH_EFLAGS_AC_PRESERVING)
# include <iprt/asm-amd64-x86.h>
# define IPRT_X86_EFL_AC RT_BIT(18)
-# define IPRT_LINUX_SAVE_EFL_AC() RTCCUINTREG fSavedEfl = ASMGetFlags();
+# define IPRT_LINUX_SAVE_EFL_AC() RTCCUINTREG fSavedEfl = ASMGetFlags()
# define IPRT_LINUX_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
-# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() ASMSetFlags((ASMGetFlags() & ~IPRT_X86_EFL_AC) | (fSavedEfl & IPRT_X86_EFL_AC))
+# define IPRT_LINUX_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~IPRT_X86_EFL_AC, fSavedEfl & IPRT_X86_EFL_AC)
#else
# define IPRT_LINUX_SAVE_EFL_AC() do { } while (0)
# define IPRT_LINUX_RESTORE_EFL_AC() do { } while (0)
diff --git a/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
index f604f4c..b5c6bba 100644
--- a/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -33,7 +33,7 @@
#include <iprt/thread.h>
#include <iprt/asm.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) || defined(CONFIG_X86_SMAP)
# include <iprt/asm-amd64-x86.h>
#endif
#include <iprt/assert.h>
@@ -59,9 +59,11 @@ RT_EXPORT_SYMBOL(RTThreadNativeSelf);
static int rtR0ThreadLnxSleepCommon(RTMSINTERVAL cMillies)
{
+ IPRT_LINUX_SAVE_EFL_AC();
long cJiffies = msecs_to_jiffies(cMillies);
set_current_state(TASK_INTERRUPTIBLE);
cJiffies = schedule_timeout(cJiffies);
+ IPRT_LINUX_RESTORE_EFL_AC();
if (!cJiffies)
return VINF_SUCCESS;
return VERR_INTERRUPTED;
@@ -84,6 +86,7 @@ RT_EXPORT_SYMBOL(RTThreadSleepNoLog);
RTDECL(bool) RTThreadYield(void)
{
+ IPRT_LINUX_SAVE_EFL_AC();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20)
yield();
#else
@@ -92,6 +95,7 @@ RTDECL(bool) RTThreadYield(void)
sys_sched_yield();
schedule();
#endif
+ IPRT_LINUX_RESTORE_EFL_AC();
return true;
}
RT_EXPORT_SYMBOL(RTThreadYield);
diff --git a/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
index 0195656..084068c 100644
--- a/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c
@@ -130,16 +130,20 @@ DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pN
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 4)
struct task_struct *NativeThread;
+ IPRT_LINUX_SAVE_EFL_AC();
RT_ASSERT_PREEMPTIBLE();
NativeThread = kthread_run(rtThreadNativeMain, pThreadInt, "iprt-%s", pThreadInt->szName);
- if (IS_ERR(NativeThread))
- return VERR_GENERAL_FAILURE;
-
- *pNativeThread = (RTNATIVETHREAD)NativeThread;
- return VINF_SUCCESS;
+ if (!IS_ERR(NativeThread))
+ {
+ *pNativeThread = (RTNATIVETHREAD)NativeThread;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+ }
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_GENERAL_FAILURE;
#else
return VERR_NOT_IMPLEMENTED;
#endif
diff --git a/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
index d02823c..741e1e3 100644
--- a/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c
@@ -163,18 +163,31 @@ DECLINLINE(void) rtThreadCtxHooksDeregister(PRTTHREADCTXINT pThis)
RTDECL(int) RTThreadCtxHooksCreate(PRTTHREADCTX phThreadCtx)
{
PRTTHREADCTXINT pThis;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ /*
+ * Validate input.
+ */
Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
pThis = (PRTTHREADCTXINT)RTMemAllocZ(sizeof(*pThis));
if (RT_UNLIKELY(!pThis))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_NO_MEMORY;
+ }
pThis->u32Magic = RTTHREADCTXINT_MAGIC;
pThis->hOwner = RTThreadNativeSelf();
pThis->fRegistered = false;
preempt_notifier_init(&pThis->hPreemptNotifier, &pThis->hPreemptOps);
pThis->cRefs = 1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ preempt_notifier_inc();
+#endif
+
*phThreadCtx = pThis;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTThreadCtxHooksCreate);
@@ -217,6 +230,8 @@ RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
cRefs = ASMAtomicDecU32(&pThis->cRefs);
if (!cRefs)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* If there's still a registered thread-context hook, deregister it now before destroying the object.
*/
@@ -230,8 +245,13 @@ RTDECL(uint32_t) RTThreadCtxHooksRelease(RTTHREADCTX hThreadCtx)
Assert(!pThis->hPreemptOps.sched_out);
Assert(!pThis->hPreemptOps.sched_in);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ preempt_notifier_dec();
+#endif
+
ASMAtomicWriteU32(&pThis->u32Magic, ~RTTHREADCTXINT_MAGIC);
RTMemFree(pThis);
+ IPRT_LINUX_RESTORE_EFL_AC();
}
else
Assert(cRefs < UINT32_MAX / 2);
@@ -243,6 +263,8 @@ RT_EXPORT_SYMBOL(RTThreadCtxHooksRelease);
RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK pfnThreadCtxHook, void *pvUser)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate input.
*/
@@ -266,6 +288,7 @@ RTDECL(int) RTThreadCtxHooksRegister(RTTHREADCTX hThreadCtx, PFNRTTHREADCTXHOOK
pThis->fRegistered = true;
preempt_notifier_register(&pThis->hPreemptNotifier);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
@@ -273,6 +296,8 @@ RT_EXPORT_SYMBOL(RTThreadCtxHooksRegister);
RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
{
+ IPRT_LINUX_SAVE_EFL_AC();
+
/*
* Validate input.
*/
@@ -289,6 +314,8 @@ RTDECL(int) RTThreadCtxHooksDeregister(RTTHREADCTX hThreadCtx)
* Deregister the callback.
*/
rtThreadCtxHooksDeregister(pThis);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTThreadCtxHooksDeregister);
@@ -307,6 +334,7 @@ RTDECL(bool) RTThreadCtxHooksAreRegistered(RTTHREADCTX hThreadCtx)
return pThis->fRegistered;
}
+RT_EXPORT_SYMBOL(RTThreadCtxHooksAreRegistered);
#else /* Not supported / Not needed */
diff --git a/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
index cd2e70f..bdc5083 100644
--- a/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c
@@ -169,14 +169,17 @@ RT_EXPORT_SYMBOL(RTTimeSystemMilliTS);
RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
{
+ IPRT_LINUX_SAVE_EFL_AC();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
struct timespec Ts;
ktime_get_real_ts(&Ts);
+ IPRT_LINUX_RESTORE_EFL_AC();
return RTTimeSpecSetTimespec(pTime, &Ts);
#else /* < 2.6.16 */
struct timeval Tv;
do_gettimeofday(&Tv);
+ IPRT_LINUX_RESTORE_EFL_AC();
return RTTimeSpecSetTimeval(pTime, &Tv);
#endif
}
diff --git a/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
index b5c875d..d2a517a 100644
--- a/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c
@@ -1185,6 +1185,7 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
{
RTTIMERLINUXSTARTONCPUARGS Args;
int rc2;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate.
@@ -1202,7 +1203,11 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
* Omni timer?
*/
if (pTimer->fAllCpus)
- return rtTimerLnxOmniStart(pTimer, &Args);
+ {
+ rc2 = rtTimerLnxOmniStart(pTimer, &Args);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc2;
+ }
#endif
/*
@@ -1233,6 +1238,7 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
return rc2;
}
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
break;
@@ -1242,12 +1248,14 @@ RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_CB_RESTARTING, enmState))
{
ASMAtomicWriteBool(&pTimer->fSuspended, false);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
break;
default:
AssertMsgFailed(("%d\n", enmState));
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_INTERNAL_ERROR_4;
}
ASMNopPause();
@@ -1328,6 +1336,7 @@ RTDECL(int) RTTimerStop(PRTTIMER pTimer)
/*
* Validate.
*/
+ IPRT_LINUX_SAVE_EFL_AC();
AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
RTTIMERLNX_LOG(("stop %p\n", pTimer));
@@ -1336,6 +1345,8 @@ RTDECL(int) RTTimerStop(PRTTIMER pTimer)
return VERR_TIMER_SUSPENDED;
rtTimerLnxStop(pTimer, false /*fForDestroy*/);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTTimerStop);
@@ -1345,6 +1356,7 @@ RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
{
unsigned long cJiffies;
unsigned long flFlags;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate.
@@ -1362,6 +1374,7 @@ RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
if (pTimer->fHighRes)
{
ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
#endif
@@ -1382,6 +1395,7 @@ RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
pTimer->cJiffies = cJiffies;
ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTTimerChangeInterval);
@@ -1390,6 +1404,7 @@ RT_EXPORT_SYMBOL(RTTimerChangeInterval);
RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
{
bool fCanDestroy;
+ IPRT_LINUX_SAVE_EFL_AC();
/*
* Validate. It's ok to pass NULL pointer.
@@ -1457,6 +1472,7 @@ RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
rtTimerLnxDestroyIt(pTimer);
}
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTTimerDestroy);
@@ -1468,6 +1484,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
RTCPUID iCpu;
unsigned cCpus;
int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
rtR0LnxWorkqueueFlush(); /* for 2.4 */
*ppTimer = NULL;
@@ -1476,11 +1493,17 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
* Validate flags.
*/
if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_INVALID_PARAMETER;
+ }
if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
&& (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
&& !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return VERR_CPU_NOT_FOUND;
+ }
/*
* Allocate the timer handler.
@@ -1491,14 +1514,17 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
{
cCpus = RTMpGetMaxCpuId() + 1;
Assert(cCpus <= RTCPUSET_MAX_CPUS); /* On linux we have a 1:1 relationship between cpuid and set index. */
- AssertReturn(u64NanoInterval, VERR_NOT_IMPLEMENTED); /* We don't implement single shot on all cpus, sorry. */
+ AssertReturnStmt(u64NanoInterval, IPRT_LINUX_RESTORE_EFL_AC(), VERR_NOT_IMPLEMENTED); /* We don't implement single shot on all cpus, sorry. */
}
#endif
rc = RTMemAllocEx(RT_OFFSETOF(RTTIMER, aSubTimers[cCpus]), 0,
RTMEMALLOCEX_FLAGS_ZEROED | RTMEMALLOCEX_FLAGS_ANY_CTX_FREE, (void **)&pTimer);
if (RT_FAILURE(rc))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
+ }
/*
* Initialize it.
@@ -1565,6 +1591,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
if (RT_FAILURE(rc))
{
RTTimerDestroy(pTimer);
+ IPRT_LINUX_RESTORE_EFL_AC();
return rc;
}
}
@@ -1572,6 +1599,7 @@ RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_
RTTIMERLNX_LOG(("create %p hires=%d fFlags=%#x cCpus=%u\n", pTimer, pTimer->fHighRes, fFlags, cCpus));
*ppTimer = pTimer;
+ IPRT_LINUX_RESTORE_EFL_AC();
return VINF_SUCCESS;
}
RT_EXPORT_SYMBOL(RTTimerCreateEx);
@@ -1582,7 +1610,10 @@ RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
#if 0 /** @todo Not sure if this is what we want or not... Add new API for
* querying the resolution of the high res timers? */
struct timespec Ts;
- int rc = hrtimer_get_res(CLOCK_MONOTONIC, &Ts);
+ int rc;
+ IPRT_LINUX_SAVE_EFL_AC();
+ rc = hrtimer_get_res(CLOCK_MONOTONIC, &Ts);
+ IPRT_LINUX_RESTORE_EFL_AC();
if (!rc)
{
Assert(!Ts.tv_sec);
diff --git a/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp b/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
index 0ffd6ca..db22bb7 100644
--- a/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
+++ b/src/VBox/Runtime/r0drv/nt/ntBldSymDb.cpp
@@ -790,6 +790,7 @@ static RTEXITCODE FigurePdbVersionInfo(const char *pszPdb, PRTNTSDBOSVER pVerInf
{ RT_STR_TUPLE("Windows_Winmain.8400"), 6, 2, 0, 8400 }, /* RC */
{ RT_STR_TUPLE("Windows_Win8.9200"), 6, 2, 0, 9200 }, /* RTM */
{ RT_STR_TUPLE("en_windows_8_1"), 6, 3, 0, 9600 }, /* RTM */
+ { RT_STR_TUPLE("en_windows_10_symbols_"), 10, 0, 0,10240 }, /* RTM */
};
const char *pszComp = u.Split.apszComps[i];
@@ -1146,7 +1147,7 @@ int main(int argc, char **argv)
break;
case 'V':
- RTPrintf("$Revision: 92629 $");
+ RTPrintf("$Revision: 101859 $");
break;
case 'h':
diff --git a/src/VBox/Runtime/r0drv/nt/symdbdata.h b/src/VBox/Runtime/r0drv/nt/symdbdata.h
index d23aca8..5558bd6 100644
--- a/src/VBox/Runtime/r0drv/nt/symdbdata.h
+++ b/src/VBox/Runtime/r0drv/nt/symdbdata.h
@@ -2912,6 +2912,50 @@ const RTNTSDBSET g_artNtSdbSets[] =
},
},
# endif
+# ifdef RT_ARCH_X86
+ { /* Source: s:\WinSyms\u\en_windows_10_symbols_x86_6903197\ntkrpamp.pdb\3A07902D18FD40CE929445D1777703241\ntkrpamp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 10,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 10240,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2239,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x21ec,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x3cfc,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
+# ifdef RT_ARCH_AMD64
+ { /* Source: s:\WinSyms\u\en_windows_10_symbols_x64_6903177\ntkrnlmp.pdb\C68EE22FDCF6477895C54A862BE165671\ntkrnlmp.pdb */
+ /*.OsVerInfo = */
+ {
+ /* .uMajorVer = */ 10,
+ /* .uMinorVer = */ 0,
+ /* .fChecked = */ false,
+ /* .fSmp = */ true,
+ /* .uCsdNo = */ 0,
+ /* .uBuildNo = */ 10240,
+ },
+ /* .KPRCB = */
+ {
+ /* .offQuantumEnd = */ 0x2de9,
+ /* .cbQuantumEnd = */ 0x0001,
+ /* .offDpcQueueDepth = */ 0x2d98,
+ /* .cbDpcQueueDepth = */ 0x0004,
+ /* .offVendorString = */ 0x6258,
+ /* .cbVendorString = */ 0x000d,
+ },
+ },
+# endif
};
#endif /* !RTNTSDB_NO_DATA */
diff --git a/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp b/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp
new file mode 100644
index 0000000..6b82afb
--- /dev/null
+++ b/src/VBox/Runtime/r3/darwin/RTCrStoreCreateSnapshotById-darwin.cpp
@@ -0,0 +1,249 @@
+/* $Id: RTCrStoreCreateSnapshotById-darwin.cpp $ */
+/** @file
+ * IPRT - RTCrStoreCreateSnapshotById, Darwin.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crypto/store.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+
+/* HACK ALERT! Shut up those deprecated messages on SecKeychainSearchCreateFromAttributes and SecKeychainSearchCopyNext. */
+#include <CoreFoundation/CoreFoundation.h>
+#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+
+#include <Security/Security.h>
+
+
+/**
+ * Checks the trust settings of the certificate.
+ *
+ * @returns true if not out-right distructed, otherwise false.
+ * @param hCert The certificate.
+ * @param enmTrustDomain The trust settings domain to check relative to.
+ */
+static bool rtCrStoreIsDarwinCertTrustworthy(SecCertificateRef hCert, SecTrustSettingsDomain enmTrustDomain)
+{
+ bool fResult = true;
+ CFArrayRef hTrustSettings;
+ OSStatus orc = SecTrustSettingsCopyTrustSettings(hCert, enmTrustDomain, &hTrustSettings);
+ if (orc == noErr)
+ {
+ CFIndex const cTrustSettings = CFArrayGetCount(hTrustSettings);
+ for (CFIndex i = 0; i < cTrustSettings; i++)
+ {
+ CFDictionaryRef hDict = (CFDictionaryRef)CFArrayGetValueAtIndex(hTrustSettings, i);
+ AssertStmt(CFGetTypeID(hDict) == CFDictionaryGetTypeID(), continue);
+
+ CFNumberRef hNum = (CFNumberRef)CFDictionaryGetValue(hDict, kSecTrustSettingsResult);
+ if (hNum)
+ {
+ AssertStmt(CFGetTypeID(hNum) == CFNumberGetTypeID(), continue);
+ SInt32 iNum;
+ if (CFNumberGetValue(hNum, kCFNumberSInt32Type, &iNum))
+ {
+ if (iNum == kSecTrustSettingsResultDeny)
+ {
+ fResult = false;
+ break;
+ }
+ }
+ /* No need to release hNum (get rule). */
+ }
+ /* No need to release hDict (get rule). */
+ }
+ CFRelease(hTrustSettings);
+ }
+ else if (orc != errSecItemNotFound)
+ {
+ AssertFailed();
+ fResult = false;
+ }
+ return fResult;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeychain(RTCRSTORE hStore, SecKeychainRef hKeychain, SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /*
+ * Enumerate the certificates in the keychain.
+ */
+ SecKeychainSearchRef hSearch;
+ OSStatus orc = SecKeychainSearchCreateFromAttributes(hKeychain, kSecCertificateItemClass, NULL, &hSearch);
+ if (orc == noErr)
+ {
+ SecKeychainItemRef hItem;
+ while ((orc = SecKeychainSearchCopyNext(hSearch, &hItem)) == noErr)
+ {
+ Assert(CFGetTypeID(hItem) == SecCertificateGetTypeID());
+ SecCertificateRef hCert = (SecCertificateRef)hItem;
+
+ /*
+ * Check if the current certificate is at all trusted, skip it if it's isn't.
+ */
+ if (rtCrStoreIsDarwinCertTrustworthy(hCert, enmTrustDomain))
+ {
+ /*
+ * Get the certificate data.
+ */
+ CFDataRef hEncodedCert = SecCertificateCopyData(hCert);
+ Assert(hEncodedCert);
+ if (hEncodedCert)
+ {
+ CFIndex cbEncoded = CFDataGetLength(hEncodedCert);
+ const uint8_t *pbEncoded = CFDataGetBytePtr(hEncodedCert);
+
+ RTERRINFOSTATIC StaticErrInfo;
+ int rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
+ pbEncoded, cbEncoded, RTErrInfoInitStatic(&StaticErrInfo));
+ if (RT_FAILURE(rc2))
+ {
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ RTErrInfoAddF(pErrInfo, -rc2, " %s", StaticErrInfo.Core.pszMsg);
+ else
+ RTErrInfoAddF(pErrInfo, -rc2, " %Rrc adding cert", rc2);
+ rc = -rc2;
+ }
+
+ CFRelease(hEncodedCert);
+ }
+ }
+
+ CFRelease(hItem);
+ }
+ if (orc != errSecItemNotFound)
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainSearchCopyNext failed with %#x", orc);
+ CFRelease(hSearch);
+ }
+ else
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainSearchCreateFromAttributes failed with %#x", orc);
+ return rc;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeychainFile(RTCRSTORE hStore, const char *pszKeychain,
+ SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /*
+ * Open the keychain and call common worker to do the job.
+ */
+ SecKeychainRef hKeychain;
+ OSStatus orc = SecKeychainOpen(pszKeychain, &hKeychain);
+ if (orc == noErr)
+ {
+ rc = rtCrStoreAddCertsFromNativeKeychain(hStore, hKeychain, enmTrustDomain, rc, pErrInfo);
+
+ CFRelease(hKeychain);
+ }
+ else if (RTFileExists(pszKeychain))
+ rc = RTErrInfoAddF(pErrInfo, -VERR_OPEN_FAILED, " SecKeychainOpen failed with %#x on '%s'", orc, pszKeychain);
+ return rc;
+}
+
+
+static int rtCrStoreAddCertsFromNativeKeystoreDomain(RTCRSTORE hStore, SecPreferencesDomain enmDomain,
+ SecTrustSettingsDomain enmTrustDomain,
+ int rc, PRTERRINFO pErrInfo)
+{
+ /*
+ * Get a list of keystores for this domain and call common worker on each.
+ */
+ CFArrayRef hKeychains;
+ OSStatus orc = SecKeychainCopyDomainSearchList(enmDomain, &hKeychains);
+ if (orc == noErr)
+ {
+ CFIndex const cEntries = CFArrayGetCount(hKeychains);
+ for (CFIndex i = 0; i < cEntries; i++)
+ {
+ SecKeychainRef hKeychain = (SecKeychainRef)CFArrayGetValueAtIndex(hKeychains, i);
+ Assert(CFGetTypeID(hKeychain) == SecKeychainGetTypeID());
+ CFRetain(hKeychain);
+
+ rc = rtCrStoreAddCertsFromNativeKeychain(hStore, hKeychain, enmTrustDomain, rc, pErrInfo);
+
+ CFRelease(hKeychain);
+ }
+
+ CFRelease(hKeychains);
+ }
+ else
+ rc = RTErrInfoAddF(pErrInfo, -VERR_SEARCH_ERROR,
+ " SecKeychainCopyDomainSearchList failed with %#x on %d", orc, enmDomain);
+ return rc;
+}
+
+
+RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo)
+{
+ AssertReturn(enmStoreId > RTCRSTOREID_INVALID && enmStoreId < RTCRSTOREID_END, VERR_INVALID_PARAMETER);
+
+ /*
+ * Create an empty in-memory store.
+ */
+ RTCRSTORE hStore;
+ int rc = RTCrStoreCreateInMem(&hStore, 128);
+ if (RT_SUCCESS(rc))
+ {
+ *phStore = hStore;
+
+ /*
+ * Load the certificates corresponding to the given virtual store ID.
+ */
+ switch (enmStoreId)
+ {
+ case RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES:
+ rc = rtCrStoreAddCertsFromNativeKeystoreDomain(hStore, kSecPreferencesDomainUser,
+ kSecTrustSettingsDomainUser, rc, pErrInfo);
+ break;
+
+ case RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES:
+ rc = rtCrStoreAddCertsFromNativeKeystoreDomain(hStore, kSecPreferencesDomainSystem,
+ kSecTrustSettingsDomainSystem, rc, pErrInfo);
+ rc = rtCrStoreAddCertsFromNativeKeychainFile(hStore,
+ "/System/Library/Keychains/SystemRootCertificates.keychain",
+ kSecTrustSettingsDomainSystem, rc, pErrInfo);
+ break;
+
+ default:
+ AssertFailed(); /* implement me */
+ }
+ }
+ else
+ RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed");
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCreateSnapshotById);
+
+
diff --git a/src/VBox/Runtime/r3/nt/fs-nt.cpp b/src/VBox/Runtime/r3/nt/fs-nt.cpp
index e89b55b..b8c279d 100644
--- a/src/VBox/Runtime/r3/nt/fs-nt.cpp
+++ b/src/VBox/Runtime/r3/nt/fs-nt.cpp
@@ -225,6 +225,11 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
}
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+ return false;
+}
+
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
{
diff --git a/src/VBox/Runtime/r3/posix/fs-posix.cpp b/src/VBox/Runtime/r3/posix/fs-posix.cpp
index d5e982e..d9e3d2d 100644
--- a/src/VBox/Runtime/r3/posix/fs-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/fs-posix.cpp
@@ -152,7 +152,11 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
* Calc/fake the returned values.
*/
pProperties->cbMaxComponent = StatVFS.f_namemax;
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ pProperties->fCaseSensitive = false;
+#else
pProperties->fCaseSensitive = true;
+#endif
pProperties->fCompressed = false;
pProperties->fFileCompression = false;
pProperties->fReadOnly = !!(StatVFS.f_flag & ST_RDONLY);
@@ -170,6 +174,16 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
}
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ return false;
+#else
+ return true;
+#endif
+}
+
+
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
{
*penmType = RTFSTYPE_UNKNOWN;
diff --git a/src/VBox/Runtime/r3/win/RTCrStoreCreateSnapshotById-win.cpp b/src/VBox/Runtime/r3/win/RTCrStoreCreateSnapshotById-win.cpp
new file mode 100644
index 0000000..4a9e185
--- /dev/null
+++ b/src/VBox/Runtime/r3/win/RTCrStoreCreateSnapshotById-win.cpp
@@ -0,0 +1,169 @@
+/* $Id: RTCrStoreCreateSnapshotById-win.cpp $ */
+/** @file
+ * IPRT - RTCrStoreCreateSnapshotById, Windows.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/crypto/store.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/once.h>
+#include <iprt/ldr.h>
+
+#include <Windows.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+typedef HCERTSTORE (WINAPI *PFNCERTOPENSTORE)(PCSTR pszStoreProvider, DWORD dwEncodingType, HCRYPTPROV_LEGACY hCryptProv,
+ DWORD dwFlags, const void *pvParam);
+typedef BOOL (WINAPI *PFNCERTCLOSESTORE)(HCERTSTORE hCertStore, DWORD dwFlags);
+typedef PCCERT_CONTEXT (WINAPI *PFNCERTENUMCERTIFICATESINSTORE)(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext);
+
+
+
+static int rtCrStoreAddCertsFromNative(RTCRSTORE hStore, DWORD fStore, PCRTUTF16 pwszStoreName,
+ PFNCERTOPENSTORE pfnOpenStore, PFNCERTCLOSESTORE pfnCloseStore,
+ PFNCERTENUMCERTIFICATESINSTORE pfnEnumCerts, int rc, PRTERRINFO pErrInfo)
+{
+ DWORD fOpenStore = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG;
+ HCERTSTORE hNativeStore = pfnOpenStore(CERT_STORE_PROV_SYSTEM_W, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+ NULL /* hCryptProv = default */, fStore | fOpenStore, pwszStoreName);
+ if (hStore)
+ {
+ PCCERT_CONTEXT pCurCtx = NULL;
+ while ((pCurCtx = pfnEnumCerts(hNativeStore, pCurCtx)) != NULL)
+ {
+ if (pCurCtx->dwCertEncodingType & X509_ASN_ENCODING)
+ {
+ RTERRINFOSTATIC StaticErrInfo;
+ RTASN1CURSORPRIMARY PrimaryCursor;
+ RTAsn1CursorInitPrimary(&PrimaryCursor, pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded,
+ RTErrInfoInitStatic(&StaticErrInfo),
+ &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "CurCtx");
+ RTCRX509CERTIFICATE MyCert;
+ int rc2 = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, &MyCert, "Cert");
+ if (RT_SUCCESS(rc2))
+ {
+ rc2 = RTCrStoreCertAddEncoded(hStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
+ pCurCtx->pbCertEncoded, pCurCtx->cbCertEncoded,
+ RTErrInfoInitStatic(&StaticErrInfo));
+ RTCrX509Certificate_Delete(&MyCert);
+ }
+ if (RT_FAILURE(rc2))
+ {
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ RTErrInfoAddF(pErrInfo, -rc2, " %s", StaticErrInfo.Core.pszMsg);
+ else
+ RTErrInfoAddF(pErrInfo, -rc2, " %Rrc adding cert", rc2);
+ rc = -rc2;
+ }
+ }
+ }
+ pfnCloseStore(hNativeStore, CERT_CLOSE_STORE_CHECK_FLAG);
+ }
+ else
+ {
+ DWORD uLastErr = GetLastError();
+ if (uLastErr != ERROR_FILE_NOT_FOUND)
+ rc = RTErrInfoAddF(pErrInfo, -RTErrConvertFromWin32(uLastErr),
+ " CertOpenStore(%#x,'%ls') failed: %u", fStore, pwszStoreName);
+ }
+ return rc;
+}
+
+
+
+RTDECL(int) RTCrStoreCreateSnapshotById(PRTCRSTORE phStore, RTCRSTOREID enmStoreId, PRTERRINFO pErrInfo)
+{
+ AssertReturn(enmStoreId > RTCRSTOREID_INVALID && enmStoreId < RTCRSTOREID_END, VERR_INVALID_PARAMETER);
+
+ /*
+ * Create an empty in-memory store.
+ */
+ RTCRSTORE hStore;
+ int rc = RTCrStoreCreateInMem(&hStore, 128);
+ if (RT_SUCCESS(rc))
+ {
+ *phStore = hStore;
+
+ /*
+ * Resolve the APIs we need to do this job.
+ */
+ RTLDRMOD hLdrMod;
+ int rc2 = RTLdrLoadSystem("crypt32.dll", false /*NoUnload*/, &hLdrMod);
+ if (RT_SUCCESS(rc2))
+ {
+ PFNCERTOPENSTORE pfnOpenStore = NULL;
+ rc2 = RTLdrGetSymbol(hLdrMod, "CertOpenStore", (void **)&pfnOpenStore);
+
+ PFNCERTCLOSESTORE pfnCloseStore = NULL;
+ if (RT_SUCCESS(rc2))
+ rc2 = RTLdrGetSymbol(hLdrMod, "CertCloseStore", (void **)&pfnCloseStore);
+
+ PFNCERTENUMCERTIFICATESINSTORE pfnEnumCerts = NULL;
+ if (RT_SUCCESS(rc2))
+ rc2 = RTLdrGetSymbol(hLdrMod, "CertEnumCertificatesInStore", (void **)&pfnEnumCerts);
+ if (RT_SUCCESS(rc2))
+ {
+ /*
+ * Do the work.
+ */
+ switch (enmStoreId)
+ {
+ case RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES:
+ case RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES:
+ {
+ DWORD fStore = enmStoreId == RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES
+ ? CERT_SYSTEM_STORE_CURRENT_USER : CERT_SYSTEM_STORE_LOCAL_MACHINE;
+ static PCRTUTF16 const s_apwszStores[] = { L"AuthRoot", L"CA", L"MY", L"Root" };
+ for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszStores); i++)
+ rc = rtCrStoreAddCertsFromNative(hStore, fStore, s_apwszStores[i], pfnOpenStore, pfnCloseStore,
+ pfnEnumCerts, rc, pErrInfo);
+ break;
+ }
+
+ default:
+ AssertFailed(); /* implement me */
+ }
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, -rc2, "Error resolving crypt32.dll APIs");
+ RTLdrClose(hLdrMod);
+ }
+ else
+ rc = RTErrInfoSetF(pErrInfo, -rc2, "Error loading crypt32.dll");
+ }
+ else
+ RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed");
+ return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCreateSnapshotById);
+
diff --git a/src/VBox/Runtime/r3/win/fileio-win.cpp b/src/VBox/Runtime/r3/win/fileio-win.cpp
index f335cd8..3dcbf25 100644
--- a/src/VBox/Runtime/r3/win/fileio-win.cpp
+++ b/src/VBox/Runtime/r3/win/fileio-win.cpp
@@ -35,10 +35,13 @@
#include <Windows.h>
#include <iprt/file.h>
-#include <iprt/path.h>
+
+#include <iprt/asm.h>
#include <iprt/assert.h>
+#include <iprt/path.h>
#include <iprt/string.h>
#include <iprt/err.h>
+#include <iprt/ldr.h>
#include <iprt/log.h>
#include "internal/file.h"
#include "internal/fs.h"
@@ -48,7 +51,8 @@
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
-
+typedef BOOL WINAPI FNVERIFYCONSOLEIOHANDLE(HANDLE);
+typedef FNVERIFYCONSOLEIOHANDLE *PFNVERIFYCONSOLEIOHANDLE; /* No, nobody fell on the keyboard, really! */
/**
* This is wrapper around the ugly SetFilePointer api.
@@ -820,14 +824,47 @@ RTR3DECL(int) RTFileQueryInfo(RTFILE hFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRAD
/*
* Query file info.
*/
+ HANDLE hHandle = (HANDLE)RTFileToNative(hFile);
+
BY_HANDLE_FILE_INFORMATION Data;
- if (!GetFileInformationByHandle((HANDLE)RTFileToNative(hFile), &Data))
+ if (!GetFileInformationByHandle(hHandle, &Data))
{
+ /*
+ * Console I/O handles make trouble here. On older windows versions they
+ * end up with ERROR_INVALID_HANDLE when handed to the above API, while on
+ * more recent ones they cause different errors to appear.
+ *
+ * Thus, we must ignore the latter and doubly verify invalid handle claims.
+ * We use the undocumented VerifyConsoleIoHandle to do this, falling back on
+ * GetFileType should it not be there.
+ */
DWORD dwErr = GetLastError();
- /* Only return if we *really* don't have a valid handle value,
- * everything else is fine here ... */
- if (dwErr != ERROR_INVALID_HANDLE)
+ if (dwErr == ERROR_INVALID_HANDLE)
+ {
+ static PFNVERIFYCONSOLEIOHANDLE s_pfnVerifyConsoleIoHandle = NULL;
+ static bool volatile s_fInitialized = false;
+ PFNVERIFYCONSOLEIOHANDLE pfnVerifyConsoleIoHandle;
+ if (s_fInitialized)
+ pfnVerifyConsoleIoHandle = s_pfnVerifyConsoleIoHandle;
+ else
+ {
+ pfnVerifyConsoleIoHandle = (PFNVERIFYCONSOLEIOHANDLE)RTLdrGetSystemSymbol("kernel32.dll", "VerifyConsoleIoHandle");
+ ASMAtomicWriteBool(&s_fInitialized, true);
+ }
+ if ( pfnVerifyConsoleIoHandle
+ ? !pfnVerifyConsoleIoHandle(hHandle)
+ : GetFileType(hHandle) == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR)
+ return VERR_INVALID_HANDLE;
+ }
+ /*
+ * On Windows 10 and (hopefully) 8.1 we get ERROR_INVALID_FUNCTION with console I/O
+ * handles. We must ignore these just like the above invalid handle error.
+ */
+ else if (dwErr != ERROR_INVALID_FUNCTION)
return RTErrConvertFromWin32(dwErr);
+
+ RT_ZERO(Data);
+ Data.dwFileAttributes = RTFS_DOS_NT_DEVICE;
}
/*
diff --git a/src/VBox/Runtime/r3/win/fs-win.cpp b/src/VBox/Runtime/r3/win/fs-win.cpp
index 586444e..87450bd 100644
--- a/src/VBox/Runtime/r3/win/fs-win.cpp
+++ b/src/VBox/Runtime/r3/win/fs-win.cpp
@@ -337,6 +337,12 @@ RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProper
}
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+ return false;
+}
+
+
/**
* Internal helper for comparing a WCHAR string with a char string.
*
diff --git a/src/VBox/Runtime/r3/xml.cpp b/src/VBox/Runtime/r3/xml.cpp
index 708e41f..e66d559 100644
--- a/src/VBox/Runtime/r3/xml.cpp
+++ b/src/VBox/Runtime/r3/xml.cpp
@@ -1732,12 +1732,19 @@ void XmlMemParser::read(const void *pvBuf, size_t cbSize,
const char *pcszFilename = strFilename.c_str();
doc.m->reset();
+ const int options = XML_PARSE_NOBLANKS /* remove blank nodes */
+ | XML_PARSE_NONET /* forbit any network access */
+#if LIBXML_VERSION >= 20700
+ | XML_PARSE_HUGE /* don't restrict the node depth
+ to 256 (bad for snapshots!) */
+#endif
+ ;
if (!(doc.m->plibDocument = xmlCtxtReadMemory(m_ctxt,
(const char*)pvBuf,
(int)cbSize,
pcszFilename,
NULL, // encoding = auto
- XML_PARSE_NOBLANKS | XML_PARSE_NONET)))
+ options)))
throw XmlError(xmlCtxtGetLastError(m_ctxt));
doc.refreshInternals();
@@ -1861,13 +1868,20 @@ void XmlFileParser::read(const RTCString &strFilename,
ReadContext context(pcszFilename);
doc.m->reset();
+ const int options = XML_PARSE_NOBLANKS /* remove blank nodes */
+ | XML_PARSE_NONET /* forbit any network access */
+#if LIBXML_VERSION >= 20700
+ | XML_PARSE_HUGE /* don't restrict the node depth
+ to 256 (bad for snapshots!) */
+#endif
+ ;
if (!(doc.m->plibDocument = xmlCtxtReadIO(m_ctxt,
ReadCallback,
CloseCallback,
&context,
pcszFilename,
NULL, // encoding = auto
- XML_PARSE_NOBLANKS | XML_PARSE_NONET)))
+ options)))
throw XmlError(xmlCtxtGetLastError(m_ctxt));
doc.refreshInternals();
diff --git a/src/VBox/Runtime/testcase/Makefile.kmk b/src/VBox/Runtime/testcase/Makefile.kmk
index ede8a9f..6e52da8 100644
--- a/src/VBox/Runtime/testcase/Makefile.kmk
+++ b/src/VBox/Runtime/testcase/Makefile.kmk
@@ -94,6 +94,7 @@ PROGRAMS += \
tstRTMp-1 \
tstOnce \
tstRTPath \
+ tstRTPathGlob \
tstRTPipe \
tstRTPoll \
tstRTPrfIO \
@@ -490,6 +491,9 @@ tstOnce_SOURCES = tstOnce.cpp
tstRTPath_TEMPLATE = VBOXR3TSTEXE
tstRTPath_SOURCES = tstRTPath.cpp
+tstRTPathGlob_TEMPLATE = VBOXR3TSTEXE
+tstRTPathGlob_SOURCES = tstRTPathGlob.cpp
+
tstRTPipe_TEMPLATE = VBOXR3TSTEXE
tstRTPipe_SOURCES = tstRTPipe.cpp
diff --git a/src/VBox/Runtime/testcase/tstRTBitOperations.cpp b/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
index d45bfcd..b4502c8 100644
--- a/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
+++ b/src/VBox/Runtime/testcase/tstRTBitOperations.cpp
@@ -162,7 +162,7 @@ int main()
MAP_CLEAR(p);
CHECK_GUARD(p);
- /* set */
+ /* bit set */
MAP_CLEAR(p);
ASMBitSet(&p->au32[0], 0);
ASMBitSet(&p->au32[0], 31);
@@ -185,7 +185,7 @@ int main()
CHECK(ASMAtomicBitTestAndSet(&p->au32[0], 16) && p->au32[0] == 0x40010001U);
CHECK(!ASMAtomicBitTestAndSet(&p->au32[0], 80) && p->au32[2] == 0x00010001U);
- /* clear */
+ /* bit clear */
MAP_SET(p);
ASMBitClear(&p->au32[0], 0);
ASMBitClear(&p->au32[0], 31);
@@ -208,6 +208,15 @@ int main()
CHECK(!ASMAtomicBitTestAndClear(&p->au32[0], 16) && p->au32[0] == ~0x40010001U);
CHECK(ASMAtomicBitTestAndClear(&p->au32[0], 80) && p->au32[2] == ~0x00010001U);
+ /* range set */
+ MAP_CLEAR(p);
+ ASMBitSetRange(&p->au32[0], 0, 5);
+ ASMBitSetRange(&p->au32[0], 6, 44);
+ ASMBitSetRange(&p->au32[0], 64, 65);
+ CHECK(p->au32[0] == 0xFFFFFFDFU);
+ CHECK(p->au32[1] == 0x00000FFFU);
+ CHECK(p->au32[2] == 0x00000001U);
+
/* toggle */
MAP_SET(p);
ASMBitToggle(&p->au32[0], 0);
diff --git a/src/VBox/Runtime/testcase/tstRTHttp.cpp b/src/VBox/Runtime/testcase/tstRTHttp.cpp
index 3885c40..8d654ab 100644
--- a/src/VBox/Runtime/testcase/tstRTHttp.cpp
+++ b/src/VBox/Runtime/testcase/tstRTHttp.cpp
@@ -27,18 +27,21 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
-#include <iprt/err.h>
#include <iprt/http.h>
-#include <iprt/mem.h>
+
+#include <iprt/err.h>
#include <iprt/file.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
#include <iprt/stream.h>
#include <iprt/string.h>
-#include <iprt/initterm.h>
#include <iprt/vfslowlevel.h>
#include <iprt/zip.h>
#define CAFILE_NAME "tstHttp-tempcafile.crt"
+#if 0
static int extractPCA3G5(RTHTTP hHttp, PRTSTREAM CAFile, uint8_t *pu8Buf, size_t cbBuf)
{
uint8_t *abSha1;
@@ -186,6 +189,7 @@ static void checkError(RTHTTP hHttp, int rc, const char *pszFile)
else
RTPrintf("Error %Rrc trying to fetch '%s'\n", rc, pszFile);
}
+#endif
int main(int argc, char **argv)
{
@@ -199,6 +203,8 @@ int main(int argc, char **argv)
return 1;
}
+#if 0 /* rewrite to modified API and use test.h! */
+
for (int i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "default"))
@@ -341,4 +347,9 @@ int main(int argc, char **argv)
// RTFileDelete(CAFILE_NAME);
return !!cErrors;
+#else
+ RTMsgError("Needs rewriting. You're better off debugging the actual code in the GUI!\n");
+ return RTEXITCODE_SKIPPED;
+#endif
}
+
diff --git a/src/VBox/Runtime/testcase/tstRTPathGlob.cpp b/src/VBox/Runtime/testcase/tstRTPathGlob.cpp
new file mode 100644
index 0000000..916efc5
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTPathGlob.cpp
@@ -0,0 +1,82 @@
+/* $Id: tstRTPathGlob.cpp $ */
+/** @file
+ * IPRT Testcase - Manual RTPathGlob test.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/path.h>
+
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+int main(int argc, char **argv)
+{
+ /*
+ * Init RT+Test.
+ */
+ RTTEST hTest;
+ int rc = RTTestInitExAndCreate(argc, &argv, 0, "tstRTPathGlob", &hTest);
+ if (rc)
+ return rc;
+ RTTestBanner(hTest);
+
+ if (argc <= 1)
+ return RTTestSkipAndDestroy(hTest, "Requires arguments");
+
+
+ /*
+ * Manual glob testing.
+ */
+ for (int i = 1; i < argc; i++)
+ {
+ uint32_t cResults = UINT32_MAX;
+ PCRTPATHGLOBENTRY pHead = (PCRTPATHGLOBENTRY)&cResults;
+ rc = RTPathGlob(argv[i], 0, &pHead, &cResults);
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "#%u '%s' -> %Rrc cResult=%u\n", i, argv[i], rc, cResults);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t iEntry = 0;
+ for (PCRTPATHGLOBENTRY pCur = pHead; pCur; pCur = pCur->pNext, iEntry++)
+ {
+ RTTestPrintf(hTest, RTTESTLVL_ALWAYS, " #%3u: '%s'\n", iEntry, pCur->szPath);
+ RTTEST_CHECK(hTest, strlen(pCur->szPath) == pCur->cchPath);
+ }
+
+ RTPathGlobFree(pHead);
+ }
+ }
+
+
+ /*
+ * Summary.
+ */
+ return RTTestSummaryAndDestroy(hTest);
+}
+
+
diff --git a/src/VBox/Runtime/testcase/tstRTUri.cpp b/src/VBox/Runtime/testcase/tstRTUri.cpp
index e94ade2..9eaddf0 100644
--- a/src/VBox/Runtime/testcase/tstRTUri.cpp
+++ b/src/VBox/Runtime/testcase/tstRTUri.cpp
@@ -38,145 +38,246 @@
* Test data *
*******************************************************************************/
-static const char *g_apcszTestURIs[] =
+static struct
{
- "foo://tt:tt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo://tt:tt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
- "foo://tt:tt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there",
- "foo:tt at example.com",
- "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "urn:example:animal:ferret:nose",
- "foo:?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo:#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo://tt:tt@example.com:8042/?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo://tt:tt@example.com:8042/",
- "foo://tt:tt@example.com:8042?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo://tt:tt@example.com:8042#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
- "foo://tt:tt@example.com:8042",
- "foo:///",
- "foo://"
-};
-
-static const char *g_apcszSchemeResult[] =
-{
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "urn",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo",
- "foo"
-};
-
-static const char *g_apcszAuthorityResult[] =
-{
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- "tt:tt at example.com:8042",
- NULL,
- NULL
-};
-
-static const char *g_apcszPathResult[] =
-{
- "/over/ <>#%\"{}|^[]`/there",
- "/over/ <>#%\"{}|^[]`/there",
- "/over/ <>#%\"{}|^[]`/there",
- "tt at example.com",
- "/over/ <>#%\"{}|^[]`/there",
- "/over/ <>#%\"{}|^[]`/there",
- "example:animal:ferret:nose",
- NULL,
- NULL,
- "/",
- "/",
- NULL,
- NULL,
- NULL,
- "/",
- NULL
-};
-
-static const char *g_apcszQueryResult[] =
+ const char *pszUri;
+ const char *pszScheme;
+ const char *pszAuthority;
+ const char *pszPath;
+ const char *pszQuery;
+ const char *pszFragment;
+
+ const char *pszUsername;
+ const char *pszPassword;
+ const char *pszHost;
+ uint32_t uPort;
+
+ const char *pszCreated;
+} g_aTests[] =
{
- "name= <>#%\"{}|^[]`ferret",
- "name= <>#%\"{}|^[]`ferret",
- NULL,
- NULL,
- "name= <>#%\"{}|^[]`ferret",
- NULL,
- NULL,
- "name= <>#%\"{}|^[]`ferret",
- NULL,
- "name= <>#%\"{}|^[]`ferret",
- NULL,
- "name= <>#%\"{}|^[]`ferret",
- NULL,
- NULL,
- NULL,
- NULL
+ { /* #0 */
+ "foo://tt:yt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ "/over/ <>#%\"{}|^[]`/there",
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #1 */
+ "foo://tt:yt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ "/over/ <>#%\"{}|^[]`/there",
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #2 */
+ "foo://tt:yt@example.com:8042/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ "/over/ <>#%\"{}|^[]`/there",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #3 */
+ "foo:tt at example.com",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ "tt at example.com",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #4 */
+ "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ "/over/ <>#%\"{}|^[]`/there",
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #5 */
+ "foo:/over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ "/over/ <>#%\"{}|^[]`/there",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #6 */
+ "urn:example:animal:ferret:nose",
+ /*.pszScheme =*/ "urn",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ "example:animal:ferret:nose",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #7 */
+ "foo:?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #8 */
+ "foo:#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ NULL,
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #9 */
+ "foo://tt:yt@example.com:8042/?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ "/",
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #10 */
+ "foo://tt:yt@example.com:8042/",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ "/",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #11 */
+ "foo://tt:yt@example.com:8042?name=%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60ferret#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ "name= <>#%\"{}|^[]`ferret",
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #12 */
+ "foo://tt:yt@example.com:8042#nose%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ "nose <>#%\"{}|^[]`",
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #13 */
+ "foo://tt:yt@example.com:8042",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "tt:yt at example.com:8042",
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ "tt",
+ /*.pszPassword =*/ "yt",
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ 8042,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #14 */
+ "foo:///",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "",
+ /*.pszPath =*/ "/",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #15 */
+ "foo://",
+ /*.pszScheme =*/ "foo",
+ /*.pszAuthority =*/ "",
+ /*.pszPath =*/ NULL,
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ NULL,
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ NULL /* same as pszUri*/,
+ },
+ { /* #16 - UTF-8 escape sequences. */
+ "http://example.com/%ce%b3%ce%bb%cf%83%ce%b1%20%e0%a4%95\xe0\xa4\x95",
+ /*.pszScheme =*/ "http",
+ /*.pszAuthority =*/ "example.com",
+ /*.pszPath =*/ "/\xce\xb3\xce\xbb\xcf\x83\xce\xb1 \xe0\xa4\x95\xe0\xa4\x95",
+ /*.pszQuery =*/ NULL,
+ /*.pszFragment =*/ NULL,
+ /*.pszUsername =*/ NULL,
+ /*.pszPassword =*/ NULL,
+ /*.pszHost =*/ "example.com",
+ /*.uPort =*/ UINT32_MAX,
+ /*.pszCreated =*/ "http://example.com/\xce\xb3\xce\xbb\xcf\x83\xce\xb1%20\xe0\xa4\x95\xe0\xa4\x95",
+ },
};
-static const char *g_apcszFragmentResult[] =
-{
- "nose <>#%\"{}|^[]`",
- NULL,
- NULL,
- NULL,
- "nose <>#%\"{}|^[]`",
- "nose <>#%\"{}|^[]`",
- NULL,
- "nose <>#%\"{}|^[]`",
- "nose <>#%\"{}|^[]`",
- "nose <>#%\"{}|^[]`",
- NULL,
- "nose <>#%\"{}|^[]`",
- "nose <>#%\"{}|^[]`",
- NULL,
- NULL,
- NULL
-};
-
-static const char *g_apcszCreateURIs[][5] =
-{
- { "foo", "tt:tt at example.com:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
- { "foo", "tt:tt at example.com:8042", "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", NULL },
- { "foo", "tt:tt at example.com:8042", "/over/ <>#%\"{}|^[]`/there", NULL, NULL },
- { "foo", NULL, "tt at example.com", NULL, NULL },
- { "foo", NULL, "/over/ <>#%\"{}|^[]`/there", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
- { "foo", NULL, "/over/ <>#%\"{}|^[]`/there", NULL, "nose <>#%\"{}|^[]`" },
- { "urn", NULL, "example:animal:ferret:nose", NULL, NULL },
- { "foo", NULL, NULL, "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
- { "foo", NULL, NULL, NULL, "nose <>#%\"{}|^[]`" },
- { "foo", "tt:tt at example.com:8042", "/", "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
- { "foo", "tt:tt at example.com:8042", "/", NULL, NULL },
- { "foo", "tt:tt at example.com:8042", NULL, "name= <>#%\"{}|^[]`ferret", "nose <>#%\"{}|^[]`" },
- { "foo", "tt:tt at example.com:8042", NULL, NULL, "nose <>#%\"{}|^[]`" },
- { "foo", "tt:tt at example.com:8042", NULL, NULL, NULL },
- { "foo", "", "/", NULL, NULL },
- { "foo", "", NULL, NULL, NULL }
-};
struct URIFILETEST
{
@@ -190,129 +291,53 @@ g_apCreateFileURIs[] =
{ "/over/ <>#%\"{}|^[]`/there", "file:///over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there", URI_FILE_FORMAT_UNIX },
{ "/", "file:///", URI_FILE_FORMAT_UNIX },
{ "/C:/over/ <>#%\"{}|^[]`/there", "file:///C:%5Cover%5C%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60%5Cthere", URI_FILE_FORMAT_UNIX },
- { "over\\ <>#%\"{}|^[]`\\there", "file:///over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there", URI_FILE_FORMAT_WIN }
+ { "\\over\\ <>#%\"{}|^[]`\\there", "file:///over/%20%3C%3E%23%25%22%7B%7D%7C%5E%5B%5D%60/there", URI_FILE_FORMAT_WIN }
};
-/**
- * Basic API checks.
- */
-static void tstScheme(size_t iCount, const char *pszUri, const char *pszTest)
-{
- char *pszResult = RTUriScheme(pszUri);
- if (pszTest)
- {
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
- }
- else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
-
- if (pszResult)
- RTStrFree(pszResult);
-}
-
-static void tstAuthority(size_t iCount, const char *pszUri, const char *pszTest)
-{
- char *pszResult = RTUriAuthority(pszUri);
- if (pszTest)
- {
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
- }
- else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- if (pszResult)
- RTStrFree(pszResult);
-}
-static void tstPath(size_t iCount, const char *pszUri, const char *pszTest)
-{
- char *pszResult = RTUriPath(pszUri);
- if (pszTest)
- {
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
- }
- else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
-
- if (pszResult)
- RTStrFree(pszResult);
-}
-
-static void tstQuery(size_t iCount, const char *pszUri, const char *pszTest)
-{
- char *pszResult = RTUriQuery(pszUri);
- if (pszTest)
- {
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
- }
- else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
-
- if (pszResult)
- RTStrFree(pszResult);
-}
-
-static void tstFragment(size_t iCount, const char *pszUri, const char *pszTest)
-{
- char *pszResult = RTUriFragment(pszUri);
- if (pszTest)
- {
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
- }
- else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
-
- if (pszResult)
- RTStrFree(pszResult);
-}
-
-static void tstCreate(size_t iCount, const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment, const char *pszTest)
+static void tstCreate(size_t idxTest, const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment, const char *pszTest)
{
char *pszResult = RTUriCreate(pszScheme, pszAuthority, pszPath, pszQuery, pszFragment);
if (pszTest)
{
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
+ RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
}
else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
if (pszResult)
RTStrFree(pszResult);
return;
}
-static void tstFileCreate(size_t iCount, const char *pszPath, const char *pszTest)
+static void tstFileCreate(size_t idxTest, const char *pszPath, const char *pszTest)
{
char *pszResult = RTUriFileCreate(pszPath);
if (pszTest)
{
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
+ RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
}
else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
if (pszResult)
RTStrFree(pszResult);
return;
}
-static void tstFilePath(size_t iCount, const char *pszUri, const char *pszTest, uint32_t uFormat)
+static void tstFilePath(size_t idxTest, const char *pszUri, const char *pszTest, uint32_t uFormat)
{
char *pszResult = RTUriFilePath(pszUri, uFormat);
if (pszTest)
{
- RTTESTI_CHECK_MSG_RETV(pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
- RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG_RETV(pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
+ RTTESTI_CHECK_MSG(RTStrCmp(pszResult, pszTest) == 0, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
}
else
- RTTESTI_CHECK_MSG(!pszResult, ("Result '%s' != '%s'", pszResult, pszTest));
+ RTTESTI_CHECK_MSG(!pszResult, ("#%u: Result '%s' != '%s'", idxTest, pszResult, pszTest));
if (pszResult)
RTStrFree(pszResult);
@@ -327,52 +352,58 @@ int main()
return rc;
RTTestBanner(hTest);
- /* Scheme */
- RTTestISubF("RTUriScheme");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszSchemeResult));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstScheme(i+1, g_apcszTestURIs[i], g_apcszSchemeResult[i]);
-
- /* Authority */
- RTTestISubF("RTUriAuthority");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszAuthorityResult));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstAuthority(i+1, g_apcszTestURIs[i], g_apcszAuthorityResult[i]);
-
- /* Path */
- RTTestISubF("RTUriPath");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszPathResult));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstPath(i+1, g_apcszTestURIs[i], g_apcszPathResult[i]);
-
- /* Query */
- RTTestISubF("RTUriQuery");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszQueryResult));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstQuery(i+1, g_apcszTestURIs[i], g_apcszQueryResult[i]);
-
- /* Fragment */
- RTTestISubF("RTUriFragment");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszFragmentResult));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstFragment(i+1, g_apcszTestURIs[i], g_apcszFragmentResult[i]);
+#define CHECK_STR_API(a_Call, a_pszExpected) \
+ do { \
+ char *pszTmp = a_Call; \
+ if (a_pszExpected) \
+ { \
+ if (!pszTmp) \
+ RTTestIFailed("#%u: %s returns NULL, expected '%s'", i, #a_Call, a_pszExpected); \
+ else if (strcmp(pszTmp, a_pszExpected)) \
+ RTTestIFailed("#%u: %s returns '%s', expected '%s'", i, #a_Call, pszTmp, a_pszExpected); \
+ } \
+ else if (pszTmp) \
+ RTTestIFailed("#%u: %s returns '%s', expected NULL", i, #a_Call, pszTmp); \
+ RTStrFree(pszTmp); \
+ } while (0)
+
+ RTTestISub("RTUriParse & RTUriParsed*");
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
+ {
+ RTURIPARSED Parsed;
+ RTTESTI_CHECK_RC(rc = RTUriParse(g_aTests[i].pszUri, &Parsed), VINF_SUCCESS);
+ if (RT_SUCCESS(rc))
+ {
+ CHECK_STR_API(RTUriParsedScheme(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszScheme);
+ CHECK_STR_API(RTUriParsedAuthority(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszAuthority);
+ CHECK_STR_API(RTUriParsedAuthorityUsername(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszUsername);
+ CHECK_STR_API(RTUriParsedAuthorityPassword(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszPassword);
+ CHECK_STR_API(RTUriParsedAuthorityHost(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszHost);
+ CHECK_STR_API(RTUriParsedPath(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszPath);
+ CHECK_STR_API(RTUriParsedQuery(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszQuery);
+ CHECK_STR_API(RTUriParsedFragment(g_aTests[i].pszUri, &Parsed), g_aTests[i].pszFragment);
+ uint32_t uPort = RTUriParsedAuthorityPort(g_aTests[i].pszUri, &Parsed);
+ if (uPort != g_aTests[i].uPort)
+ RTTestIFailed("#%u: RTUriParsedAuthorityPort returns %#x, expected %#x", i, uPort, g_aTests[i].uPort);
+ }
+ }
/* Creation */
- RTTestISubF("RTUriCreate");
- Assert(RT_ELEMENTS(g_apcszTestURIs) == RT_ELEMENTS(g_apcszCreateURIs));
- for (size_t i = 0; i < RT_ELEMENTS(g_apcszTestURIs); ++i)
- tstCreate(i+1, g_apcszCreateURIs[i][0], g_apcszCreateURIs[i][1], g_apcszCreateURIs[i][2],
- g_apcszCreateURIs[i][3], g_apcszCreateURIs[i][4], g_apcszTestURIs[i]);
+ RTTestISub("RTUriCreate");
+ for (uint32_t i = 0; i < RT_ELEMENTS(g_aTests); i++)
+ CHECK_STR_API(RTUriCreate(g_aTests[i].pszScheme, g_aTests[i].pszAuthority, g_aTests[i].pszPath,
+ g_aTests[i].pszQuery, g_aTests[i].pszFragment),
+ g_aTests[i].pszCreated ? g_aTests[i].pszCreated : g_aTests[i].pszUri);
/* File Uri path */
- RTTestISubF("RTUriFilePath");
+ RTTestISub("RTUriFilePath");
for (size_t i = 0; i < RT_ELEMENTS(g_apCreateFileURIs); ++i)
- tstFilePath(i+1, g_apCreateFileURIs[i].pcszUri, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].uFormat);
+ tstFilePath(i, g_apCreateFileURIs[i].pcszUri, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].uFormat);
/* File Uri creation */
- RTTestISubF("RTUriFileCreate");
+ RTTestISub("RTUriFileCreate");
for (size_t i = 0; i < 3; ++i)
- tstFileCreate(i+1, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].pcszUri);
+ tstFileCreate(i, g_apCreateFileURIs[i].pcszPath, g_apCreateFileURIs[i].pcszUri);
return RTTestSummaryAndDestroy(hTest);
}
diff --git a/src/VBox/Runtime/tools/Makefile.kmk b/src/VBox/Runtime/tools/Makefile.kmk
index 40f0592..6a2914a 100644
--- a/src/VBox/Runtime/tools/Makefile.kmk
+++ b/src/VBox/Runtime/tools/Makefile.kmk
@@ -62,6 +62,13 @@ if !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS) && !defined(VBOX_ONLY_VALIDATIONKIT)
RTGzip_TEMPLATE = VBoxR3Tool
RTGzip_SOURCES = RTGzip.cpp
+ ifdef VBOX_WITH_LIBCURL
+ # RTHttp - our http/https fetcher (for testing the http client API).
+ PROGRAMS += RTHttp
+ RTHttp_TEMPLATE = VBoxR3Tool
+ RTHttp_SOURCES = RTHttp.cpp
+ endif
+
# RTShutdown - similar (but not identical) to a typical unix shutdown command.
PROGRAMS += RTShutdown
RTShutdown_TEMPLATE = VBoxR3Tool
diff --git a/src/VBox/Runtime/tools/RTHttp.cpp b/src/VBox/Runtime/tools/RTHttp.cpp
new file mode 100644
index 0000000..1088006
--- /dev/null
+++ b/src/VBox/Runtime/tools/RTHttp.cpp
@@ -0,0 +1,157 @@
+/* $Id: RTHttp.cpp $ */
+/** @file
+ * IPRT - Utility for retriving URLs.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/http.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/vfs.h>
+
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+
+ /*
+ * Create a HTTP client instance.
+ */
+ RTHTTP hHttp;
+ rc = RTHttpCreate(&hHttp);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTHttpCreate failed: %Rrc", rc);
+
+ /*
+ * Parse arguments.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--output", 'o', RTGETOPT_REQ_STRING },
+ { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ };
+
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ const char *pszOutput = NULL;
+ unsigned uVerbosityLevel = 1;
+
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ while ((rc = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ switch (rc)
+ {
+ case 'o':
+ pszOutput = ValueUnion.psz;
+ break;
+
+ case 'q':
+ uVerbosityLevel--;
+ break;
+ case 'v':
+ uVerbosityLevel++;
+ break;
+
+ case 'h':
+ RTPrintf("Usage: %s [options] URL0 [URL1 [...]]\n"
+ "\n"
+ "Options:\n"
+ " -o,--output=file\n"
+ " Output file. If not given, the file is displayed on stdout.\n"
+ " -q, --quiet\n"
+ " -v, --verbose\n"
+ " Controls the verbosity level.\n"
+ " -h, -?, --help\n"
+ " Display this help text and exit successfully.\n"
+ " -V, --version\n"
+ " Display the revision and exit successfully.\n"
+ , RTPathFilename(argv[0]));
+ return RTEXITCODE_SUCCESS;
+
+ case 'V':
+ RTPrintf("$Revision: 103347 $\n");
+ return RTEXITCODE_SUCCESS;
+
+ case VINF_GETOPT_NOT_OPTION:
+ {
+ int rcHttp;
+ if (pszOutput && strcmp("-", pszOutput))
+ {
+ if (uVerbosityLevel > 0)
+ RTStrmPrintf(g_pStdErr, "Fetching '%s' into '%s'...\n", ValueUnion.psz, pszOutput);
+ rcHttp = RTHttpGetFile(hHttp, ValueUnion.psz, pszOutput);
+ }
+ else
+ {
+ if (uVerbosityLevel > 0)
+ RTStrmPrintf(g_pStdErr, "Fetching '%s'...\n", ValueUnion.psz);
+
+ void *pvResp;
+ size_t cbResp;
+ rcHttp = RTHttpGetBinary(hHttp, ValueUnion.psz, &pvResp, &cbResp);
+ if (RT_SUCCESS(rcHttp))
+ {
+ RTVFSIOSTREAM hVfsIos;
+ rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, 0, true /*fLeaveOpen*/, &hVfsIos);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTVfsIoStrmWrite(hVfsIos, pvResp, cbResp, true /*fBlocking*/, NULL);
+ if (RT_FAILURE(rc))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error writing to stdout: %Rrc", rc);
+ RTVfsIoStrmRelease(hVfsIos);
+ }
+ else
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening stdout: %Rrc", rc);
+ RTHttpFreeResponse(pvResp);
+ }
+ }
+ if (RT_FAILURE(rcHttp))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error %Rrc getting '%s'", rcHttp, ValueUnion.psz);
+ break;
+ }
+
+ default:
+ return RTGetOptPrintError(rc, &ValueUnion);
+ }
+ }
+
+ return rcExit;
+}
+
+
diff --git a/src/VBox/Runtime/tools/RTSignTool.cpp b/src/VBox/Runtime/tools/RTSignTool.cpp
index 51554b9..66f1ad0 100644
--- a/src/VBox/Runtime/tools/RTSignTool.cpp
+++ b/src/VBox/Runtime/tools/RTSignTool.cpp
@@ -495,11 +495,14 @@ static RTEXITCODE HandleVerifyExe(int cArgs, char **papszArgs)
switch (ch)
{
case 'r': case 'a':
- rc = RTCrStoreCertAddFromFile(ch == 'r' ? State.hRootStore : State.hAdditionalStore, 0, ValueUnion.psz,
- RTErrInfoInitStatic(&StaticErrInfo));
+ rc = RTCrStoreCertAddFromFile(ch == 'r' ? State.hRootStore : State.hAdditionalStore,
+ RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+ ValueUnion.psz, RTErrInfoInitStatic(&StaticErrInfo));
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading certificate '%s': %Rrc - %s",
ValueUnion.psz, rc, StaticErrInfo.szMsg);
+ if (RTErrInfoIsSet(&StaticErrInfo.Core))
+ RTMsgWarning("Warnings loading certificate '%s': %s", ValueUnion.psz, StaticErrInfo.szMsg);
break;
case 't':
diff --git a/src/VBox/VMM/VMMR0/VMMR0.cpp b/src/VBox/VMM/VMMR0/VMMR0.cpp
index 95641b3..213f647 100644
--- a/src/VBox/VMM/VMMR0/VMMR0.cpp
+++ b/src/VBox/VMM/VMMR0/VMMR0.cpp
@@ -61,6 +61,48 @@
/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** SMAP check setup. */
+#define VMM_CHECK_SMAP_SETUP() uint32_t const fKernelFeatures = SUPR0GetKernelFeatures()
+/** Checks that the AC flag is set if SMAP is enabled. If AC is not set, it
+ * will be logged and @a a_BadExpr is executed. */
+#define VMM_CHECK_SMAP_CHECK(a_BadExpr) \
+ do { \
+ if (fKernelFeatures & SUPKERNELFEATURES_SMAP) \
+ { \
+ RTCCUINTREG fEflCheck = ASMGetFlags(); \
+ if (RT_LIKELY(fEflCheck & X86_EFL_AC)) \
+ { /* likely */ } \
+ else \
+ { \
+ SUPR0Printf("%s, line %d: EFLAGS.AC is clear! (%#x)\n", __FUNCTION__, __LINE__, (uint32_t)fEflCheck); \
+ a_BadExpr; \
+ } \
+ } \
+ } while (0)
+/** Checks that the AC flag is set if SMAP is enabled. If AC is not set, it
+ * will be logged, written to the VMs assertion text buffer, and @a a_BadExpr is
+ * executed. */
+#define VMM_CHECK_SMAP_CHECK2(a_pVM, a_BadExpr) \
+ do { \
+ if (fKernelFeatures & SUPKERNELFEATURES_SMAP) \
+ { \
+ RTCCUINTREG fEflCheck = ASMGetFlags(); \
+ if (RT_LIKELY(fEflCheck & X86_EFL_AC)) \
+ { /* likely */ } \
+ else \
+ { \
+ SUPR0BadContext((a_pVM) ? (a_pVM)->pSession : NULL, __FILE__, __LINE__, "EFLAGS.AC is zero!"); \
+ RTStrPrintf(pVM->vmm.s.szRing0AssertMsg1, sizeof(pVM->vmm.s.szRing0AssertMsg1), \
+ "%s, line %d: EFLAGS.AC is clear! (%#x)\n", __FUNCTION__, __LINE__, (uint32_t)fEflCheck); \
+ a_BadExpr; \
+ } \
+ } \
+ } while (0)
+
+
+/*******************************************************************************
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN
@@ -819,6 +861,8 @@ VMMR0DECL(void) VMMR0EntryFast(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperati
if (RT_UNLIKELY(idCpu >= pVM->cCpus))
return;
PVMCPU pVCpu = &pVM->aCpus[idCpu];
+ VMM_CHECK_SMAP_SETUP();
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
switch (enmOperation)
{
@@ -1003,6 +1047,7 @@ VMMR0DECL(void) VMMR0EntryFast(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperati
pVCpu->vmm.s.iLastGZRc = VERR_NOT_SUPPORTED;
break;
}
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
}
@@ -1076,7 +1121,9 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
SUPR0Printf("vmmR0EntryExWorker: Invalid idCpu=%u\n", idCpu);
return VERR_INVALID_PARAMETER;
}
-
+ VMM_CHECK_SMAP_SETUP();
+ VMM_CHECK_SMAP_CHECK(RT_NOTHING);
+ int rc;
switch (enmOperation)
{
@@ -1086,87 +1133,112 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_GVMM_CREATE_VM:
if (pVM || u64Arg || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
+ rc = GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK(RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_DESTROY_VM:
if (pReqHdr || u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0DestroyVM(pVM);
+ rc = GVMMR0DestroyVM(pVM);
+ VMM_CHECK_SMAP_CHECK(RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_REGISTER_VMCPU:
{
if (!pVM)
return VERR_INVALID_PARAMETER;
- return GVMMR0RegisterVCpu(pVM, idCpu);
+ rc = GVMMR0RegisterVCpu(pVM, idCpu);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
case VMMR0_DO_GVMM_SCHED_HALT:
if (pReqHdr)
return VERR_INVALID_PARAMETER;
- return GVMMR0SchedHalt(pVM, idCpu, u64Arg);
+ rc = GVMMR0SchedHalt(pVM, idCpu, u64Arg);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_SCHED_WAKE_UP:
if (pReqHdr || u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0SchedWakeUp(pVM, idCpu);
+ rc = GVMMR0SchedWakeUp(pVM, idCpu);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_SCHED_POKE:
if (pReqHdr || u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0SchedPoke(pVM, idCpu);
+ rc = GVMMR0SchedPoke(pVM, idCpu);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0SchedWakeUpAndPokeCpusReq(pVM, (PGVMMSCHEDWAKEUPANDPOKECPUSREQ)pReqHdr);
+ rc = GVMMR0SchedWakeUpAndPokeCpusReq(pVM, (PGVMMSCHEDWAKEUPANDPOKECPUSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_SCHED_POLL:
if (pReqHdr || u64Arg > 1)
return VERR_INVALID_PARAMETER;
- return GVMMR0SchedPoll(pVM, idCpu, !!u64Arg);
+ rc = GVMMR0SchedPoll(pVM, idCpu, !!u64Arg);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_QUERY_STATISTICS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
+ rc = GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GVMM_RESET_STATISTICS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
+ rc = GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* Initialize the R0 part of a VM instance.
*/
case VMMR0_DO_VMMR0_INIT:
- return vmmR0InitVM(pVM, RT_LODWORD(u64Arg), RT_HIDWORD(u64Arg));
+ rc = vmmR0InitVM(pVM, RT_LODWORD(u64Arg), RT_HIDWORD(u64Arg));
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* Terminate the R0 part of a VM instance.
*/
case VMMR0_DO_VMMR0_TERM:
- return VMMR0TermVM(pVM, NULL);
+ rc = VMMR0TermVM(pVM, NULL);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* Attempt to enable hm mode and check the current setting.
*/
case VMMR0_DO_HM_ENABLE:
- return HMR0EnableAllCpus(pVM);
+ rc = HMR0EnableAllCpus(pVM);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* Setup the hardware accelerated session.
*/
case VMMR0_DO_HM_SETUP_VM:
- return HMR0SetupVM(pVM);
+ rc = HMR0SetupVM(pVM);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* Switch to RC to execute Hypervisor function.
*/
case VMMR0_DO_CALL_HYPERVISOR:
{
- int rc;
- bool fVTxDisabled;
-
#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
if (RT_UNLIKELY(!PGMGetHyperCR3(VMMGetCpu0(pVM))))
return VERR_PGM_NO_CR3_SHADOW_ROOT;
@@ -1179,19 +1251,26 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
CPUMR0SetLApic(&pVM->aCpus[0], idHostCpu);
#endif
- /* We might need to disable VT-x if the active switcher turns off paging. */
+ /*
+ * We might need to disable VT-x if the active switcher turns off paging.
+ */
+ bool fVTxDisabled;
rc = HMR0EnterSwitcher(pVM, pVM->vmm.s.enmSwitcher, &fVTxDisabled);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Go through the wormhole...
+ */
+ rc = pVM->vmm.s.pfnR0ToRawMode(pVM);
- /* Re-enable VT-x if previously turned off. */
- HMR0LeaveSwitcher(pVM, fVTxDisabled);
+ /* Re-enable VT-x if previously turned off. */
+ HMR0LeaveSwitcher(pVM, fVTxDisabled);
+ }
/** @todo dispatch interrupts? */
ASMSetFlags(fFlags);
- return rc;
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
/*
@@ -1200,22 +1279,30 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
- return PGMR0PhysAllocateHandyPages(pVM, &pVM->aCpus[idCpu]);
+ rc = PGMR0PhysAllocateHandyPages(pVM, &pVM->aCpus[idCpu]);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_PGM_FLUSH_HANDY_PAGES:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
- return PGMR0PhysFlushHandyPages(pVM, &pVM->aCpus[idCpu]);
+ rc = PGMR0PhysFlushHandyPages(pVM, &pVM->aCpus[idCpu]);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
- return PGMR0PhysAllocateLargeHandyPage(pVM, &pVM->aCpus[idCpu]);
+ rc = PGMR0PhysAllocateLargeHandyPage(pVM, &pVM->aCpus[idCpu]);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_PGM_PHYS_SETUP_IOMMU:
if (idCpu != 0)
return VERR_INVALID_CPU_ID;
- return PGMR0PhysSetupIommu(pVM);
+ rc = PGMR0PhysSetupIommu(pVM);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* GMM wrappers.
@@ -1223,68 +1310,92 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_GMM_INITIAL_RESERVATION:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0InitialReservationReq(pVM, idCpu, (PGMMINITIALRESERVATIONREQ)pReqHdr);
+ rc = GMMR0InitialReservationReq(pVM, idCpu, (PGMMINITIALRESERVATIONREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_UPDATE_RESERVATION:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0UpdateReservationReq(pVM, idCpu, (PGMMUPDATERESERVATIONREQ)pReqHdr);
+ rc = GMMR0UpdateReservationReq(pVM, idCpu, (PGMMUPDATERESERVATIONREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_ALLOCATE_PAGES:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0AllocatePagesReq(pVM, idCpu, (PGMMALLOCATEPAGESREQ)pReqHdr);
+ rc = GMMR0AllocatePagesReq(pVM, idCpu, (PGMMALLOCATEPAGESREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_FREE_PAGES:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0FreePagesReq(pVM, idCpu, (PGMMFREEPAGESREQ)pReqHdr);
+ rc = GMMR0FreePagesReq(pVM, idCpu, (PGMMFREEPAGESREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_FREE_LARGE_PAGE:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0FreeLargePageReq(pVM, idCpu, (PGMMFREELARGEPAGEREQ)pReqHdr);
+ rc = GMMR0FreeLargePageReq(pVM, idCpu, (PGMMFREELARGEPAGEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0QueryHypervisorMemoryStatsReq(pVM, (PGMMMEMSTATSREQ)pReqHdr);
+ rc = GMMR0QueryHypervisorMemoryStatsReq(pVM, (PGMMMEMSTATSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_QUERY_MEM_STATS:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0QueryMemoryStatsReq(pVM, idCpu, (PGMMMEMSTATSREQ)pReqHdr);
+ rc = GMMR0QueryMemoryStatsReq(pVM, idCpu, (PGMMMEMSTATSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_BALLOONED_PAGES:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0BalloonedPagesReq(pVM, idCpu, (PGMMBALLOONEDPAGESREQ)pReqHdr);
+ rc = GMMR0BalloonedPagesReq(pVM, idCpu, (PGMMBALLOONEDPAGESREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_MAP_UNMAP_CHUNK:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr);
+ rc = GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_SEED_CHUNK:
if (pReqHdr)
return VERR_INVALID_PARAMETER;
- return GMMR0SeedChunk(pVM, idCpu, (RTR3PTR)u64Arg);
+ rc = GMMR0SeedChunk(pVM, idCpu, (RTR3PTR)u64Arg);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_REGISTER_SHARED_MODULE:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0RegisterSharedModuleReq(pVM, idCpu, (PGMMREGISTERSHAREDMODULEREQ)pReqHdr);
+ rc = GMMR0RegisterSharedModuleReq(pVM, idCpu, (PGMMREGISTERSHAREDMODULEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0UnregisterSharedModuleReq(pVM, idCpu, (PGMMUNREGISTERSHAREDMODULEREQ)pReqHdr);
+ rc = GMMR0UnregisterSharedModuleReq(pVM, idCpu, (PGMMUNREGISTERSHAREDMODULEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_RESET_SHARED_MODULES:
if (idCpu == NIL_VMCPUID)
@@ -1292,7 +1403,9 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
if ( u64Arg
|| pReqHdr)
return VERR_INVALID_PARAMETER;
- return GMMR0ResetSharedModules(pVM, idCpu);
+ rc = GMMR0ResetSharedModules(pVM, idCpu);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
#ifdef VBOX_WITH_PAGE_SHARING
case VMMR0_DO_GMM_CHECK_SHARED_MODULES:
@@ -1309,7 +1422,7 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
# ifdef DEBUG_sandervl
/* Make sure that log flushes can jump back to ring-3; annoying to get an incomplete log (this is risky though as the code doesn't take this into account). */
/* Todo: this can have bad side effects for unexpected jumps back to r3. */
- int rc = GMMR0CheckSharedModulesStart(pVM);
+ rc = GMMR0CheckSharedModulesStart(pVM);
if (rc == VINF_SUCCESS)
{
rc = vmmR0CallRing3SetJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, GMMR0CheckSharedModules, pVM, pVCpu); /* this may resume code. */
@@ -1318,9 +1431,10 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
GMMR0CheckSharedModulesEnd(pVM);
}
# else
- int rc = GMMR0CheckSharedModules(pVM, pVCpu);
+ rc = GMMR0CheckSharedModules(pVM, pVCpu);
# endif
- return rc;
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
#endif
@@ -1328,18 +1442,24 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_GMM_FIND_DUPLICATE_PAGE:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0FindDuplicatePageReq(pVM, (PGMMFINDDUPLICATEPAGEREQ)pReqHdr);
+ rc = GMMR0FindDuplicatePageReq(pVM, (PGMMFINDDUPLICATEPAGEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
#endif
case VMMR0_DO_GMM_QUERY_STATISTICS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0QueryStatisticsReq(pVM, (PGMMQUERYSTATISTICSSREQ)pReqHdr);
+ rc = GMMR0QueryStatisticsReq(pVM, (PGMMQUERYSTATISTICSSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_GMM_RESET_STATISTICS:
if (u64Arg)
return VERR_INVALID_PARAMETER;
- return GMMR0ResetStatisticsReq(pVM, (PGMMRESETSTATISTICSSREQ)pReqHdr);
+ rc = GMMR0ResetStatisticsReq(pVM, (PGMMRESETSTATISTICSSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
/*
* A quick GCFGM mock-up.
@@ -1353,7 +1473,6 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
PGCFGMVALUEREQ pReq = (PGCFGMVALUEREQ)pReqHdr;
if (pReq->Hdr.cbReq != sizeof(*pReq))
return VERR_INVALID_PARAMETER;
- int rc;
if (enmOperation == VMMR0_DO_GCFGM_SET_VALUE)
{
rc = GVMMR0SetConfig(pReq->pSession, &pReq->szName[0], pReq->u64Value);
@@ -1366,7 +1485,8 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
//if (rc == VERR_CFGM_VALUE_NOT_FOUND)
// rc = GMMR0QueryConfig(pReq->pSession, &pReq->szName[0], &pReq->u64Value);
}
- return rc;
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
/*
@@ -1376,14 +1496,18 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
{
if (!pVM || !pReqHdr || u64Arg || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return PDMR0DriverCallReqHandler(pVM, (PPDMDRIVERCALLREQHANDLERREQ)pReqHdr);
+ rc = PDMR0DriverCallReqHandler(pVM, (PPDMDRIVERCALLREQHANDLERREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
case VMMR0_DO_PDM_DEVICE_CALL_REQ_HANDLER:
{
if (!pVM || !pReqHdr || u64Arg || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return PDMR0DeviceCallReqHandler(pVM, (PPDMDEVICECALLREQHANDLERREQ)pReqHdr);
+ rc = PDMR0DeviceCallReqHandler(pVM, (PPDMDEVICECALLREQHANDLERREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
/*
@@ -1394,48 +1518,67 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
PINTNETOPENREQ pReq = (PINTNETOPENREQ)pReqHdr;
if (u64Arg || !pReq || !vmmR0IsValidSession(pVM, pReq->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0OpenReq(pSession, pReq);
+ rc = IntNetR0OpenReq(pSession, pReq);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
}
case VMMR0_DO_INTNET_IF_CLOSE:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFCLOSEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfCloseReq(pSession, (PINTNETIFCLOSEREQ)pReqHdr);
+ rc = IntNetR0IfCloseReq(pSession, (PINTNETIFCLOSEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
+
case VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFGETBUFFERPTRSREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfGetBufferPtrsReq(pSession, (PINTNETIFGETBUFFERPTRSREQ)pReqHdr);
+ rc = IntNetR0IfGetBufferPtrsReq(pSession, (PINTNETIFGETBUFFERPTRSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfSetPromiscuousModeReq(pSession, (PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr);
+ rc = IntNetR0IfSetPromiscuousModeReq(pSession, (PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETMACADDRESSREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfSetMacAddressReq(pSession, (PINTNETIFSETMACADDRESSREQ)pReqHdr);
+ rc = IntNetR0IfSetMacAddressReq(pSession, (PINTNETIFSETMACADDRESSREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_SET_ACTIVE:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETACTIVEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfSetActiveReq(pSession, (PINTNETIFSETACTIVEREQ)pReqHdr);
+ rc = IntNetR0IfSetActiveReq(pSession, (PINTNETIFSETACTIVEREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_SEND:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSENDREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfSendReq(pSession, (PINTNETIFSENDREQ)pReqHdr);
+ rc = IntNetR0IfSendReq(pSession, (PINTNETIFSENDREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_WAIT:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFWAITREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfWaitReq(pSession, (PINTNETIFWAITREQ)pReqHdr);
+ rc = IntNetR0IfWaitReq(pSession, (PINTNETIFWAITREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
case VMMR0_DO_INTNET_IF_ABORT_WAIT:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFWAITREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return IntNetR0IfAbortWaitReq(pSession, (PINTNETIFABORTWAITREQ)pReqHdr);
+ rc = IntNetR0IfAbortWaitReq(pSession, (PINTNETIFABORTWAITREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
#ifdef VBOX_WITH_PCI_PASSTHROUGH
/*
@@ -1444,7 +1587,9 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_PCIRAW_REQ:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PPCIRAWSENDREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
- return PciRawR0ProcessReq(pSession, pVM, (PPCIRAWSENDREQ)pReqHdr);
+ rc = PciRawR0ProcessReq(pSession, pVM, (PPCIRAWSENDREQ)pReqHdr);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
#endif
/*
* For profiling.
@@ -1465,7 +1610,9 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
case VMMR0_DO_TEST_SWITCHER3264:
if (idCpu == NIL_VMCPUID)
return VERR_INVALID_CPU_ID;
- return HMR0TestSwitcher3264(pVM);
+ rc = HMR0TestSwitcher3264(pVM);
+ VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+ break;
#endif
default:
/*
@@ -1475,6 +1622,7 @@ static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperatio
Log(("operation %#x is not supported\n", enmOperation));
return VERR_NOT_SUPPORTED;
}
+ return rc;
}
diff --git a/src/VBox/VMM/VMMR3/PDMDriver.cpp b/src/VBox/VMM/VMMR3/PDMDriver.cpp
index b9c40d3..e96a887 100644
--- a/src/VBox/VMM/VMMR3/PDMDriver.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDriver.cpp
@@ -683,7 +683,7 @@ int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDM
rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
else
rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
- if (pNew)
+ if (RT_SUCCESS(rc))
{
/*
* Initialize the instance structure (declaration order).
@@ -774,10 +774,7 @@ int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDM
}
}
else
- {
- AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'\n", cb, pszName));
- rc = VERR_NO_MEMORY;
- }
+ AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'! rc=%Rrc\n", cb, pszName, rc));
}
else
AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
diff --git a/src/libs/Makefile.kmk b/src/libs/Makefile.kmk
index 3765bf0..a298562 100644
--- a/src/libs/Makefile.kmk
+++ b/src/libs/Makefile.kmk
@@ -27,20 +27,20 @@ include $(KBUILD_PATH)/subheader.kmk
# Compression libs used by IPRT and <what was it again?>.
include $(PATH_SUB_CURRENT)/liblzf-3.4/Makefile.kmk
if !defined(VBOX_ONLY_SDK) \
- && "$(SDK_VBOX_ZLIB_INCS)" == "$(PATH_ROOT)/src/libs/zlib-1.2.6"
- include $(PATH_SUB_CURRENT)/zlib-1.2.6/Makefile.kmk
+ && "$(SDK_VBOX_ZLIB_INCS)" == "$(PATH_ROOT)/src/libs/zlib-1.2.8"
+ include $(PATH_SUB_CURRENT)/zlib-1.2.8/Makefile.kmk
endif
# PNG support (for screenshots).
if !defined(VBOX_ONLY_DOCS) && !defined(VBOX_ONLY_SDK) && !defined(VBOX_ONLY_TESTSUITE) \
- && "$(SDK_VBOX_LIBPNG_INCS)" == "$(PATH_ROOT)/src/libs/libpng-1.2.8"
- include $(PATH_SUB_CURRENT)/libpng-1.2.8/Makefile.kmk
+ && "$(SDK_VBOX_LIBPNG_INCS)" == "$(PATH_ROOT)/src/libs/libpng-1.2.53"
+ include $(PATH_SUB_CURRENT)/libpng-1.2.53/Makefile.kmk
endif # !VBOX_ONLY_DOCS
# Libcurl for inet access
if defined(VBOX_WITH_LIBCURL) && !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS) && !defined(VBOX_ONLY_SDK) && !defined(VBOX_ONLY_TESTSUITE) \
- && "$(SDK_VBOX_LIBCURL_INCS)" == "$(PATH_ROOT)/src/libs/curl-7.42.1/include"
- include $(PATH_SUB_CURRENT)/curl-7.42.1/Makefile.kmk
+ && "$(SDK_VBOX_LIBCURL_INCS)" == "$(PATH_ROOT)/src/libs/curl-7.45.0/include"
+ include $(PATH_SUB_CURRENT)/curl-7.45.0/Makefile.kmk
endif
# The kStuff lib used by IPRT and the debugger.
@@ -78,8 +78,8 @@ if defined(VBOX_WITH_MAIN) \
endif
if !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS)
- ifeq ($(SDK_VBOX_LIBXML2_INCS),$(PATH_ROOT)/src/libs/libxml2-2.6.31/include)
- include $(PATH_SUB_CURRENT)/libxml2-2.6.31/Makefile.kmk
+ ifeq ($(SDK_VBOX_LIBXML2_INCS),$(PATH_ROOT)/src/libs/libxml2-2.9.2/include)
+ include $(PATH_SUB_CURRENT)/libxml2-2.9.2/Makefile.kmk
endif
endif
diff --git a/src/libs/xpcom18a4/python/__init__.py b/src/libs/xpcom18a4/python/__init__.py
old mode 100644
new mode 100755
diff --git a/src/libs/xpcom18a4/python/components.py b/src/libs/xpcom18a4/python/components.py
old mode 100644
new mode 100755
diff --git a/src/libs/xpcom18a4/python/nsError.py b/src/libs/xpcom18a4/python/nsError.py
old mode 100644
new mode 100755
diff --git a/src/libs/xpcom18a4/python/tools/tracer_demo.py b/src/libs/xpcom18a4/python/tools/tracer_demo.py
old mode 100644
new mode 100755
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/virtualbox.git
More information about the Pkg-virtualbox-commits
mailing list