[Pkg-virtualbox-commits] [virtualbox] 01/03: New upstream version 5.2.8-dfsg
Gianfranco Costamagna
locutusofborg at moszumanska.debian.org
Tue Feb 27 22:34:53 UTC 2018
This is an automated email from the git hooks/post-receive script.
locutusofborg pushed a commit to branch master
in repository virtualbox.
commit f5dd37b1dd0376577f1260b4ee9d0bce885b9496
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Tue Feb 27 23:27:05 2018 +0100
New upstream version 5.2.8-dfsg
---
Config.kmk | 57 +-
Makefile.kmk | 8 +-
Version.kmk | 2 +-
doc/manual/en_US/user_Installation.xml | 2 +-
doc/manual/en_US/user_VBoxManage.xml | 7 +
doc/manual/user_ChangeLogImpl.xml | 108 +
include/VBox/disopcode.h | 4 +
include/VBox/err.h | 3 +
include/VBox/settings.h | 2 +
include/VBox/shflsvc.h | 2 +
include/VBox/sup.h | 1 +
include/VBox/vmm/cpum.h | 21 +-
include/VBox/vmm/cpumctx.h | 2 +
include/VBox/vmm/iem.h | 1 +
include/VBox/vmm/pdmstorageifs.h | 22 +-
include/VBox/vscsi.h | 15 +
include/iprt/linux/symvers.h | 58 +
include/iprt/mangling.h | 1 +
include/iprt/time.h | 15 +
include/iprt/x86.h | 20 +-
.../Additions/common/VBoxGuest/VBoxGuest-linux.c | 24 +-
src/VBox/Additions/common/crOpenGL/entrypoints.pyc | Bin 5904 -> 5904 bytes
src/VBox/Additions/linux/drm/vbox_mode.c | 4 +
src/VBox/Additions/linux/installer/install.sh.in | 2 +
src/VBox/Additions/linux/installer/vboxadd-x11.sh | 5 +-
src/VBox/Additions/linux/installer/vboxadd.sh | 59 +-
src/VBox/Additions/linux/sharedfolders/utils.c | 9 +-
src/VBox/Additions/x11/VBoxClient/Makefile.kmk | 15 +
src/VBox/Additions/x11/VBoxClient/chk_stubs.c | 56 +
src/VBox/Devices/Audio/AudioMixBuffer.cpp | 40 +-
src/VBox/Devices/Audio/AudioMixBuffer.h | 7 +-
src/VBox/Devices/Audio/DevHDA.cpp | 375 ++--
src/VBox/Devices/Audio/DevHDA.h | 6 +-
src/VBox/Devices/Audio/DevHDACommon.cpp | 35 +-
src/VBox/Devices/Audio/DevHDACommon.h | 4 +-
src/VBox/Devices/Audio/DevSB16.cpp | 61 +-
src/VBox/Devices/Audio/DrvAudio.cpp | 100 +-
src/VBox/Devices/Audio/DrvAudio.h | 5 +-
src/VBox/Devices/Audio/DrvAudioCommon.cpp | 90 +-
src/VBox/Devices/Audio/DrvHostDSound.cpp | 1254 ++++++-----
src/VBox/Devices/Audio/DrvHostPulseAudio.cpp | 26 +-
src/VBox/Devices/Audio/HDACodec.cpp | 75 -
src/VBox/Devices/Audio/HDAStream.cpp | 253 ++-
src/VBox/Devices/Audio/HDAStream.h | 23 +-
.../Devices/Audio/testcase/tstAudioMixBuffer.cpp | 23 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative286.asm | 6 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum | 2 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative386.asm | 6 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum | 2 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative8086.asm | 6 +-
.../BIOS/VBoxVgaBiosAlternative8086.md5sum | 2 +-
src/VBox/Devices/Network/DevE1000.cpp | 11 +-
.../Devices/PC/BIOS/VBoxBiosAlternative286.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative286.md5sum | 2 +-
.../Devices/PC/BIOS/VBoxBiosAlternative386.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative386.md5sum | 2 +-
.../Devices/PC/BIOS/VBoxBiosAlternative8086.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum | 2 +-
src/VBox/Devices/PC/DevPcArch.cpp | 64 +-
src/VBox/Devices/Serial/DevSerial.cpp | 8 +-
src/VBox/Devices/Storage/DevAHCI.cpp | 66 +-
src/VBox/Devices/Storage/DevATA.cpp | 4 +-
src/VBox/Devices/Storage/DrvHostDVD.cpp | 30 +-
src/VBox/Devices/Storage/DrvSCSI.cpp | 16 +
src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h | 25 +-
src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp | 13 +-
src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp | 13 +-
src/VBox/Devices/USB/VUSBDevice.cpp | 6 +
src/VBox/Devices/VirtIO/Virtio.cpp | 9 +
.../Devices/testcase/tstDeviceStructSizeRC.cpp | 3 +-
src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp | 1 +
.../Frontends/VBoxManage/VBoxManageModifyVM.cpp | 6 +
src/VBox/Frontends/VirtualBox/Makefile.kmk | 7 -
src/VBox/Frontends/VirtualBox/VirtualBoxMac.qrc | 12 -
src/VBox/Frontends/VirtualBox/VirtualBoxOther.qrc | 10 -
src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts | 10 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts | 112 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts | 10 +-
src/VBox/Frontends/VirtualBox/nls/qt_id.ts | 2300 ++++++++++----------
src/VBox/Frontends/VirtualBox/src/VBoxAboutDlg.cpp | 2 +-
.../src/extradata/UIExtraDataManager.cpp | 2 +-
.../Frontends/VirtualBox/src/globals/UIDefs.cpp | 3 +-
src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h | 3 +-
.../src/globals/UIDesktopWidgetWatchdog.cpp | 17 +
.../src/globals/UIDesktopWidgetWatchdog.h | 5 +
.../VirtualBox/src/globals/UIIconPool.cpp | 3 +-
.../Frontends/VirtualBox/src/globals/UIVersion.h | 128 ++
.../VirtualBox/src/globals/VBoxGlobal.cpp | 28 +-
.../Frontends/VirtualBox/src/globals/VBoxVersion.h | 80 -
.../Frontends/VirtualBox/src/medium/UIMedium.cpp | 2 +-
.../VirtualBox/src/net/UIDownloaderAdditions.cpp | 30 +-
.../src/net/UIDownloaderExtensionPack.cpp | 21 +-
.../VirtualBox/src/net/UIDownloaderUserManual.cpp | 10 +-
.../VirtualBox/src/net/UINetworkReply.cpp | 21 +-
.../Frontends/VirtualBox/src/net/UINetworkReply.h | 11 +-
.../VirtualBox/src/net/UINetworkRequest.cpp | 100 +-
.../Frontends/VirtualBox/src/net/UIUpdateDefs.cpp | 8 +-
.../Frontends/VirtualBox/src/net/UIUpdateDefs.h | 14 +-
.../VirtualBox/src/net/UIUpdateManager.cpp | 32 +-
.../src/platform/darwin/UICocoaSpecialControls.mm | 2 +-
src/VBox/Frontends/VirtualBox/src/precomp.h | 2 +-
.../VirtualBox/src/runtime/UIMachineLogic.cpp | 4 +-
.../VirtualBox/src/runtime/UIMachineWindow.cpp | 23 +-
.../VirtualBox/src/selector/UISelectorWindow.cpp | 2 +-
.../src/settings/UISettingsSerializer.cpp | 2 +-
.../Frontends/VirtualBox/src/wizards/UIWizard.cpp | 4 +-
src/VBox/GuestHost/OpenGL/Makefile.kmk | 2 -
src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.pyc | Bin 23671 -> 23671 bytes
.../GuestHost/OpenGL/packer/pack_currenttypes.pyc | Bin 2110 -> 2110 bytes
.../GuestHost/OpenGL/state_tracker/convert.pyc | Bin 2087 -> 2087 bytes
.../OpenGL/state_tracker/get_components.pyc | Bin 5791 -> 5791 bytes
src/VBox/HostDrivers/Support/SUPDrv.cpp | 53 +-
src/VBox/HostDrivers/Support/SUPDrvIOC.h | 4 +-
src/VBox/HostDrivers/Support/SUPDrvInternal.h | 1 +
src/VBox/HostDrivers/Support/SUPLib.cpp | 8 +-
src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp | 66 +
.../VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp | 162 +-
src/VBox/HostServices/GuestProperties/service.cpp | 37 +
.../GuestProperties/testcase/tstGuestPropSvc.cpp | 11 +
src/VBox/HostServices/SharedFolders/vbsf.cpp | 6 +-
.../SharedOpenGL/crserverlib/get_sizes.pyc | Bin 17777 -> 17777 bytes
.../HostServices/SharedOpenGL/render/renderspu.h | 1 +
.../SharedOpenGL/render/renderspu_cocoa_helper.m | 3 -
.../SharedOpenGL/render/renderspu_config.c | 16 +
.../SharedOpenGL/render/renderspu_glx.c | 43 +-
.../SharedOpenGL/render/renderspu_wgl.c | 43 +-
src/VBox/Installer/Config.kmk | 3 +
src/VBox/Installer/linux/routines.sh | 9 +
src/VBox/Installer/win/Makefile.kmk | 27 +-
src/VBox/Installer/win/VirtualBox.wxs | 15 +-
src/VBox/Main/UnattendedTemplates/Makefile.kmk | 3 +
.../Main/UnattendedTemplates/debian_postinstall.sh | 26 +-
.../Main/UnattendedTemplates/redhat_postinstall.sh | 28 +-
src/VBox/Main/UnattendedTemplates/rhel3_ks.cfg | 141 ++
src/VBox/Main/UnattendedTemplates/rhel4_ks.cfg | 120 +
src/VBox/Main/UnattendedTemplates/rhel5_ks.cfg | 119 +
src/VBox/Main/idl/VirtualBox.xidl | 17 +-
src/VBox/Main/include/MachineImpl.h | 2 +
src/VBox/Main/include/UnattendedImpl.h | 9 +
src/VBox/Main/include/UnattendedInstaller.h | 74 +-
src/VBox/Main/src-client/ConsoleImpl2.cpp | 9 +
src/VBox/Main/src-client/EBML_MKV.h | 3 +-
src/VBox/Main/src-client/VideoRec.cpp | 2 +-
src/VBox/Main/src-client/WebMWriter.cpp | 180 +-
src/VBox/Main/src-client/WebMWriter.h | 85 +-
src/VBox/Main/src-server/MachineImpl.cpp | 26 +
src/VBox/Main/src-server/UnattendedImpl.cpp | 400 +++-
src/VBox/Main/src-server/UnattendedInstaller.cpp | 28 +-
src/VBox/Main/xml/Settings.cpp | 18 +-
src/VBox/Runtime/Makefile.kmk | 1 +
src/VBox/Runtime/common/asn1/asn1-ut-time.cpp | 16 +-
src/VBox/Runtime/common/fs/isomakercmd.cpp | 11 +-
src/VBox/Runtime/common/fs/isomakerimport.cpp | 12 +-
src/VBox/Runtime/common/misc/getopt.cpp | 4 +-
src/VBox/Runtime/common/time/time.cpp | 202 ++
src/VBox/Runtime/r3/fileio.cpp | 6 +-
src/VBox/Runtime/testcase/tstRTGetOpt.cpp | 14 +
src/VBox/Storage/QCOW.cpp | 4 +-
src/VBox/Storage/VMDK.cpp | 4 +-
src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp | 78 +
src/VBox/VMM/VMMAll/IEMAll.cpp | 67 +
src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h | 147 +-
.../VMM/VMMAll/IEMAllInstructionsThree0f38.cpp.h | 35 +-
.../VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h | 110 +-
src/VBox/VMM/VMMR0/HMVMXR0.cpp | 43 +-
src/VBox/VMM/VMMR0/VMMR0.cpp | 17 +-
src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp | 172 +-
src/VBox/VMM/VMMR3/HM.cpp | 7 +
src/VBox/VMM/VMMR3/PDMDevice.cpp | 8 +-
src/VBox/VMM/VMMR3/VMM.cpp | 14 +-
src/VBox/VMM/include/HMInternal.h | 4 +-
src/VBox/VMM/testcase/tstIEMCheckMc.cpp | 6 +
172 files changed, 5874 insertions(+), 3147 deletions(-)
diff --git a/Config.kmk b/Config.kmk
index d029f75..2cf57cf 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -18,7 +18,6 @@
# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
#
-
# Marker.
VBOX_ROOT_CONFIG_KMK_INCLUDED = 1
@@ -4674,6 +4673,15 @@ TEMPLATE_VBOXR3EXE_CXXFLAGS = -g $(VBOX_GCC_pipe) $(VBOX_GCC_PEDANTIC
ifdef VBOX_WITH_NO_GCC_WARNING_POLICY
TEMPLATE_VBOXR3EXE_CXXFLAGS += $(VBOX_GCC_WERR)
endif
+ ifdef VBOX_WITH_OLD_GLIBC_SUPPORT
+ # Use older versions of APIs which were improved in versions of glibc later
+ # than what we are targetting, and do not use the stack protector, which
+ # needs glibc 2.4 or later.
+ TEMPLATE_VBOXR3EXE_CXXFLAGS.linux = \
+ -include $(PATH_ROOT)/include/iprt/linux/symvers.h \
+ $(VBOX_GCC_fno-stack-protector)
+ TEMPLATE_VBOXR3EXE_CFLAGS.linux = $(TEMPLATE_VBOXR3EXE_CXXFLAGS.linux)
+ endif
TEMPLATE_VBOXR3EXE_CXXFLAGS.x86 = -m32
TEMPLATE_VBOXR3EXE_CXXFLAGS.amd64 = -m64
TEMPLATE_VBOXR3EXE_CXXFLAGS.sparc32 = -m32
@@ -4705,6 +4713,10 @@ TEMPLATE_VBOXR3EXE_LDFLAGS.amd64 = -m64
TEMPLATE_VBOXR3EXE_LDFLAGS.sparc32 = -m32
TEMPLATE_VBOXR3EXE_LDFLAGS.sparc64 = -m64
TEMPLATE_VBOXR3EXE_LDFLAGS.linux = -Wl,-z,noexecstack,-z,relro $(VBOX_LD_as_needed)
+ ifdef VBOX_WITH_OLD_GLIBC_SUPPORT
+ # The GNU_HASH ELF tag is not supported by older systems.
+TEMPLATE_VBOXR3EXE_LDFLAGS.linux += -Wl,--hash-style=sysv
+ endif
TEMPLATE_VBOXR3EXE_LDFLAGS.solaris = -Wl,-z,ignore # same as VBOX_LD_as_needed
TEMPLATE_VBOXR3EXE_LDFLAGS.debug = $(VBOX_GCC_SANITIZER_FLAGS)
@@ -6450,11 +6462,6 @@ ifeq ($(KBUILD_TARGET),win)
TEMPLATE_VBOXGUESTR3EXE_LIBS.win.x86 = $(NO_SUCH_VARIABLE)# Ditch RuntimeR3VccTricks2
endif
else # the gcc guys
- ifdef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
- ifneq ($(KBUILD_TARGET),linux)
- override VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE :=
- endif
- endif
TEMPLATE_VBOXGUESTR3EXE_EXTENDS = VBOXR3EXE
TEMPLATE_VBOXGUESTR3EXE_TOOL := $(subst GXX,GCC,$(TEMPLATE_VBOXR3EXE_TOOL))
TEMPLATE_VBOXGUESTR3EXE_CXXFLAGS = $(TEMPLATE_VBOXR3EXE_CXXFLAGS) -fno-exceptions
@@ -6463,23 +6470,6 @@ else # the gcc guys
TEMPLATE_VBOXGUESTR3EXE_CFLAGS.debug = $(NO_SUCH_VARIABLE)
TEMPLATE_VBOXGUESTR3EXE_LDFLAGS.linux = $(filter-out $(VBOX_GCC_ORIGIN_OPT),$(TEMPLATE_VBOXR3EXE_LDFLAGS.linux))
TEMPLATE_VBOXGUESTR3EXE_LDFLAGS.debug = $(NO_SUCH_VARIABLE)
- ifdef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
- ifeq ($(KBUILD_TARGET_ARCH),x86)
- TEMPLATE_VBOXGUESTR3EXE_TOOL := VBoxXGccX86RedHatLinux
- else ifeq ($(KBUILD_TARGET_ARCH),amd64)
- TEMPLATE_VBOXGUESTR3EXE_TOOL := VBoxXGccAmd64LinuxGnu
- TEMPLATE_VBOXGUESTR3EXE_TOOL.x86 := VBoxXGccX86RedHatLinux
- endif
- TEMPLATE_VBOXGUESTR3EXE_CXXFLAGS := $(filter-out $(VBOX_GCC_Wextra) $(VBOX_GCC_WERR) \
- $(VBOX_GCC_Wno-missing-field-initializers) $(VBOX_GCC_fdiagnostics-show-option) $(VBOX_GCC_Wno-variadic-macros) \
- $(VBOX_GCC_fvisibility-hidden) $(VBOX_GCC_fvisibility-inlines-hidden) $(VBOX_GCC_mtune-generic) $(VBOX_GCC_Wlogical-op)\
- ,$(TEMPLATE_VBOXGUESTR3EXE_CXXFLAGS)) -pipe
- TEMPLATE_VBOXGUESTR3EXE_CFLAGS := $(filter-out $(VBOX_GCC_Wextra) $(VBOX_GCC_WERR) \
- $(VBOX_GCC_Wno-missing-field-initializers) $(VBOX_GCC_fdiagnostics-show-option) $(VBOX_GCC_Wno-variadic-macros) \
- $(VBOX_GCC_fvisibility-hidden) $(VBOX_GCC_fvisibility-inlines-hidden) $(VBOX_GCC_mtune-generic) $(VBOX_GCC_Wlogical-op)\
- ,$(TEMPLATE_VBOXGUESTR3EXE_CFLAGS)) -pipe
- TEMPLATE_VBOXGUESTR3EXE_LDFLAGS.linux := $(filter-out $(VBOX_GCC_ORIGIN_OPT) $(VBOX_LD_as_needed),$(TEMPLATE_VBOXGUESTR3EXE_LDFLAGS.linux))
- endif
TEMPLATE_VBOXGUESTR3EXE_LDFLAGS = $(filter-out '$(VBOX_GCC_RPATH_OPT)%,$(TEMPLATE_VBOXR3EXE_LDFLAGS))
endif
TEMPLATE_VBOXGUESTR3EXE_INST = $(INST_ADDITIONS)
@@ -6518,7 +6508,7 @@ ifeq ($(KBUILD_TARGET),win)
TEMPLATE_VBoxGuestR3Exe_CXXFLAGS += -wd4313
endif
TEMPLATE_VBoxGuestR3Exe_LDFLAGS += $(VBOX_VCC_LD_WERR)
-else ifndef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
+else
TEMPLATE_VBoxGuestR3Exe_CFLAGS += $(VBOX_GCC_WERR)
TEMPLATE_VBoxGuestR3Exe_CXXFLAGS += $(VBOX_GCC_WERR)
endif
@@ -6558,7 +6548,7 @@ ifeq ($(KBUILD_TARGET),win)
TEMPLATE_VBoxGuestR3Dll_CFLAGS += $(VBOX_VCC_WERR)
TEMPLATE_VBoxGuestR3Dll_CXXFLAGS += $(VBOX_VCC_WERR)
TEMPLATE_VBoxGuestR3Dll_LDFLAGS += $(VBOX_VCC_LD_WERR)
-else ifndef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
+else
TEMPLATE_VBoxGuestR3Dll_CFLAGS += $(VBOX_GCC_WERR)
TEMPLATE_VBoxGuestR3Dll_CXXFLAGS += $(VBOX_GCC_WERR)
endif
@@ -6599,7 +6589,7 @@ ifeq ($(KBUILD_TARGET),win)
TEMPLATE_VBoxGuestR3Lib_CFLAGS += $(VBOX_VCC_WERR)
TEMPLATE_VBoxGuestR3Lib_CXXFLAGS += $(VBOX_VCC_WERR)
TEMPLATE_VBoxGuestR3Lib_LDFLAGS += $(VBOX_VCC_LD_WERR)
-else ifndef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
+else
TEMPLATE_VBoxGuestR3Lib_CFLAGS += $(VBOX_GCC_WERR)
TEMPLATE_VBoxGuestR3Lib_CXXFLAGS += $(VBOX_GCC_WERR)
endif
@@ -6646,6 +6636,10 @@ TEMPLATE_VBOXGUESTR3XF86MOD_EXTENDS = VBOXGUESTR3EXE
TEMPLATE_VBOXGUESTR3XF86MOD_LIBS.$(KBUILD_TYPE) = $(NO_SUCH_VARIABLE)
TEMPLATE_VBOXGUESTR3XF86MOD_LIBS.$(KBUILD_TARGET) = $(NO_SUCH_VARIABLE)
TEMPLATE_VBOXGUESTR3XF86MOD_LDFLAGS.$(KBUILD_TARGET) = $(NO_SUCH_VARIABLE)
+ifdef VBOX_WITH_OLD_GLIBC_SUPPORT
+# The GNU_HASH ELF tag is not supported by older systems.
+TEMPLATE_VBOXGUESTR3XF86MOD_LDFLAGS.linux = --hash-style=sysv
+endif
TEMPLATE_VBOXGUESTR3XF86MOD_LDFLAGS.$(KBUILD_TYPE) = $(NO_SUCH_VARIABLE)
TEMPLATE_VBOXGUESTR3XF86MOD_LDFLAGS = -r
if1of ($(KBUILD_TARGET), dragonfly freebsd linux netbsd openbsd) # the gnu ld guys.
@@ -6655,10 +6649,6 @@ if1of ($(KBUILD_TARGET), dragonfly freebsd linux netbsd openbsd) # the gnu ld gu
endif
TEMPLATE_VBOXGUESTR3XF86MOD_CFLAGS = $(TEMPLATE_VBOXGUESTR3EXE_CFLAGS) -fno-pie -fno-merge-constants -std=c99 -ffreestanding
TEMPLATE_VBOXGUESTR3XF86MOD_CXXFLAGS= $(TEMPLATE_VBOXGUESTR3EXE_CXXFLAGS) -fno-pie -fno-merge-constants -ffreestanding
-ifndef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
- TEMPLATE_VBOXGUESTR3XF86MOD_CFLAGS += $(VBOX_GCC_fno-stack-protector)
- TEMPLATE_VBOXGUESTR3XF86MOD_CXXFLAGS += $(VBOX_GCC_fno-stack-protector)
-endif
TEMPLATE_VBOXGUESTR3XF86MOD_SYSSUFF = .o
TEMPLATE_VBOXGUESTR3XF86MOD_LIBS = \
$(VBOX_LIB_VBGL_R3_XFREE86)
@@ -6684,9 +6674,6 @@ TEMPLATE_VBOXGUESTR3XORGMOD_LIBS.$(KBUILD_TARGET) = $(NO_SUCH_VARIABLE)
TEMPLATE_VBOXGUESTR3XORGMOD_CFLAGS = $(TEMPLATE_VBOXGUESTR3DLL_CFLAGS) -std=c99
if1of ($(KBUILD_TARGET), linux)
TEMPLATE_VBOXGUESTR3XORGMOD_CFLAGS += -Wno-conversion -Wno-unused-parameter
- ifndef VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE
- TEMPLATE_VBOXGUESTR3XORGMOD_CFLAGS += $(VBOX_GCC_Wno-variadic-macros)
- endif
endif
TEMPLATE_VBOXGUESTR3XORGMOD_DEFS = $(TEMPLATE_VBOXGUESTR3DLL_DEFS) VBOX_GUESTR3XORGMOD RTMEM_NO_WRAP_TO_EF_APIS
ifeq ($(KBUILD_TARGET_ARCH),amd64)
@@ -6826,7 +6813,7 @@ ifeq ($(KBUILD_TARGET),win)
-wd4255 -wd4296 -wd4245 -wd4668 -wd4005 -wd4057 -wd4311 -wd4312 -wd4305 -wd4306 -wd4054 -wd4189 -wd4100
else
TEMPLATE_VBOXCROGLR3GUESTDLL_CFLAGS = $(filter-out -pedantic, $(TEMPLATE_$(TEMPLATE_VBOXCROGLR3GUESTDLL_EXTENDS)_CFLAGS)) \
- $(if-expr !defined(VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE),$(VBOX_GCC_Wno-overlength-strings),)
+ $(VBOX_GCC_Wno-overlength-strings)
TEMPLATE_VBOXCROGLR3GUESTDLL_CXXFLAGS = $(filter-out -pedantic, $(TEMPLATE_$(TEMPLATE_VBOXCROGLR3GUESTDLL_EXTENDS)_CXXFLAGS))
endif
TEMPLATE_VBOXCROGLR3GUESTDLL_LDFLAGS.darwin = $(TEMPLATE_$(TEMPLATE_VBOXCROGLR3GUESTDLL_EXTENDS)_LDFLAGS.darwin)\
@@ -7097,7 +7084,7 @@ endif
SVN ?= svn$(HOSTSUFF_EXE)
VBOX_SVN_REV_KMK = $(PATH_OUT)/revision.kmk
ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 120293 $ )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 120774 $ )
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/Makefile.kmk b/Makefile.kmk
index a3cbe4d..4b7fc2a 100644
--- a/Makefile.kmk
+++ b/Makefile.kmk
@@ -1298,7 +1298,7 @@ extpacks-build-solaris.rsync-into-vm: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
extpacks-build-solaris.build-it: extpacks-build-solaris.rsync-into-vm
$(call VBOX_BLD_VM_MSG_BEGIN,Solaris/amd64 extension packs)
- $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/amd64 && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
+ $(VBOX_KMK_TIME) ssh -v vbox@$(VBOX_BLD_VM_SOLARIS_IP) " echo $@/amd64 && cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
$(call VBOX_BLD_VM_MSG_END__,Solaris/amd64 extension packs)
extpacks-build-solaris.rsync-out-of-vm: extpacks-build-solaris.build-it
@@ -1332,10 +1332,10 @@ extpacks-build-linux.rsync-into-vm: $(VBOX_EXTPACKS_BUILD_WIN_HOST_FIRST)
extpacks-build-linux.build-it: extpacks-build-linux.rsync-into-vm
$(call VBOX_BLD_VM_MSG_BEGIN,Linux/amd64 extension packs)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@/amd64 && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all\""'
+ $(VBOX_KMK_TIME) ssh '-v vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@/amd64 && dchroot -c debian-4.0-amd64 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all\""'
$(call VBOX_BLD_VM_MSG_END__,Linux/amd64 extension packs)
$(call VBOX_BLD_VM_MSG_BEGIN,Linux/x86 extension packs)
- $(VBOX_KMK_TIME) ssh 'vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@/x86 && linux32 dchroot -c debian-4.0-i386 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all\""'
+ $(VBOX_KMK_TIME) ssh '-v vbox@$(VBOX_BLD_VM_LNX_IP) " echo $@/x86 && linux32 dchroot -c debian-4.0-i386 \"cd /mnt/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.x86) all\""'
$(call VBOX_BLD_VM_MSG_END__,Linux/x86 extension packs)
extpacks-build-linux.rsync-out-of-vm: extpacks-build-linux.build-it
@@ -1372,7 +1372,7 @@ ifeq ($(KBUILD_TARGET).$(KBUILD_TARGET_ARCH),darwin.amd64)
else
$(call VBOX_BLD_VM_MSG_BEGIN,Darwin/amd64 extension packs)
$(VBOX_KMK_TIME) $(call VBOX_RSYNC_IN_FN,darwin,amd64) . $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)
- $(VBOX_KMK_TIME) ssh vbox@$(VBOX_BLD_VM_DARWIN_AMD64_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
+ $(VBOX_KMK_TIME) ssh -v vbox@$(VBOX_BLD_VM_DARWIN_AMD64_IP) " echo $@ && cd /Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME) && tools/env.sh --no-wine kmk $(VBOX_EXTPACKS_BUILD.amd64) all"
$(VBOX_KMK_TIME) rsync -am -v --delete $(VBOX_BLD_VM_DARWIN_AMD64_IP):/Users/vbox/tinderbox/$(VBOX_EXTPACKS_BUILD_SUBDIRNAME)/out/darwin.amd64 out/
$(call VBOX_BLD_VM_MSG_END__,Darwin/amd64 extension packs)
endif
diff --git a/Version.kmk b/Version.kmk
index e9b2d23..462b891 100644
--- a/Version.kmk
+++ b/Version.kmk
@@ -25,7 +25,7 @@ VBOX_VERSION_MINOR = 2
# 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 = 6
+VBOX_VERSION_BUILD = 8
# This can be overridden in LocalConfig.kmk or elsewhere.
# For the convention, see checks near the end of Config.kmk.
VBOX_BUILD_PUBLISHER =
diff --git a/doc/manual/en_US/user_Installation.xml b/doc/manual/en_US/user_Installation.xml
index c159c75..0979ef5 100644
--- a/doc/manual/en_US/user_Installation.xml
+++ b/doc/manual/en_US/user_Installation.xml
@@ -277,7 +277,7 @@
<listitem>
<para>A window will open telling you to double click on the
- <computeroutput>VirtualBox.mpkg</computeroutput> installer file
+ <computeroutput>VirtualBox.pkg</computeroutput> installer file
displayed in that window.</para>
</listitem>
diff --git a/doc/manual/en_US/user_VBoxManage.xml b/doc/manual/en_US/user_VBoxManage.xml
index 09a403a..acff7d0 100644
--- a/doc/manual/en_US/user_VBoxManage.xml
+++ b/doc/manual/en_US/user_VBoxManage.xml
@@ -627,6 +627,13 @@ UUID="457af700-bc0a-4258-aa3c-13b03da171f2"
</listitem>
<listitem>
+ <para><computeroutput>--spec-ctrl on|off</computeroutput>: This setting
+ enables/disables exposing speculation control interfaces to the guest, provided
+ they are available on the host. Depending on the host CPU and workload, enabling
+ speculation control may significantly reduce performance.</para>
+ </listitem>
+
+ <listitem>
<para><computeroutput>--cpu-profile <host|intel 80[86|286|386]></computeroutput>:
This enables specification of a profile for guest cpu emulation.
Specify either one based on the host system CPU (host), or one from
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index 6edfaa2..d3582cd 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -4,6 +4,114 @@
So, we use chapter and xpointer="xpointer(/chapter/)" with xi:include. -->
<sect1>
+ <title>Version 5.2.8 (2018-02-27)</title>
+
+ <para>This is a maintenance release. The following items were fixed and/or
+ added:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>VMM: added support for FSGSBASE, PCID, INVPCID CPU features for guests</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: fixed EMM386 issue with detecting suitable page frame base (bug #10022)</para>
+ </listitem>
+
+ <listitem>
+ <para>Front end: Linux: prevent VM window from jumping and auto-resizing to tiny size after resizing it on HiDPI screen</para>
+ </listitem>
+
+ <listitem>
+ <para>Front end: Linux: fixed seamless regression caused by wm_class functionality (bugs #12534, #17304)</para>
+ </listitem>
+
+ <listitem>
+ <para>Front end: switched to https downloads</para>
+ </listitem>
+
+ <listitem>
+ <para>Front end: fixed crash while opening New machine wizard (s.a. forums topic 86592)</para>
+ </listitem>
+
+ <listitem>
+ <para>Audio: added support for distinguishing recording sources in the PulseAudio
+ mixer on the host when multiple VMs are running</para>
+ </listitem>
+
+ <listitem>
+ <para>Audio: various fixes for the DirectSound backend</para>
+ </listitem>
+
+ <listitem>
+ <para>Video recording: added better file seeking support and fixed playback
+ of recorded files with certain players (e.g. Firefox)</para>
+ </listitem>
+
+ <listitem>
+ <para>Audio: various fixes for Windows guest surround setups</para>
+ </listitem>
+
+ <listitem>
+ <para>Audio: various fixes for HDA emulation</para>
+ </listitem>
+
+ <listitem>
+ <para>Serial: fixed an issue where the serial port parameters in the emulation
+ and host serial port got out of sync (bug #17116)</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: fixed overwriting certain INQUIRY data for the DVD/CD drive
+ attached to a AHCI controller</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: fixed handling VMDK images created by Amazon EC2 VM export</para>
+ </listitem>
+
+ <listitem>
+ <para>Network: fixed PXE boot regression in e1000</para>
+ </listitem>
+
+ <listitem>
+ <para>Network: Added a workaround for older guests which do not enable
+ bus mastering for the virtio PCI device</para>
+ </listitem>
+
+ <listitem>
+ <para>3D: add environment variable to configure presenting 3D content on
+ main thread (see bug #13653)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows hosts: fixed indiscriminate binding of NDIS5 bridged driver,
+ that caused PPPOE malfunction (bugs #16407, #17489)</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows guests: fixed incorrect function error when using
+ shared folders in certain applications (bug #14118)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux guests: Linux 4.15 support (bugs #17311, #17320, #17282)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux guests: fixed black screen when 3D enabled in guests
+ (bug #17463, 5.2.6 regression)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux guests: suppress setuid and setgid in shared folders</para>
+ </listitem>
+
+ </itemizedlist>
+ </sect1>
+
+ <sect1>
<title>Version 5.2.6 (2018-01-15)</title>
<para>This is a maintenance release. The following items were fixed and/or
diff --git a/include/VBox/disopcode.h b/include/VBox/disopcode.h
index b06bbd8..516dd6f 100644
--- a/include/VBox/disopcode.h
+++ b/include/VBox/disopcode.h
@@ -727,6 +727,10 @@ enum OPCODES
OP_XSAVE,
OP_XSAVEOPT,
OP_XRSTOR,
+ OP_RDFSBASE,
+ OP_RDGSBASE,
+ OP_WRFSBASE,
+ OP_WRGSBASE,
OP_LFENCE,
OP_MFENCE,
OP_SFENCE,
diff --git a/include/VBox/err.h b/include/VBox/err.h
index a8a8107..3bd4bce 100644
--- a/include/VBox/err.h
+++ b/include/VBox/err.h
@@ -1863,6 +1863,9 @@
#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 (-3749)
+
+/** Raw-mode is unavailable courtesy of Hyper-V. */
+#define VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT (-7000)
/** @} */
diff --git a/include/VBox/settings.h b/include/VBox/settings.h
index 35d0c87..6dd4b15 100644
--- a/include/VBox/settings.h
+++ b/include/VBox/settings.h
@@ -906,6 +906,8 @@ struct Hardware
fX2APIC; // requires settings version 1.16 (VirtualBox 5.1)
bool fIBPBOnVMExit; //< added out of cycle, after 1.16 was out.
bool fIBPBOnVMEntry; //< added out of cycle, after 1.16 was out.
+ bool fSpecCtrl; //< added out of cycle, after 1.16 was out.
+ bool fSpecCtrlByHost; //< added out of cycle, after 1.16 was out.
typedef enum LongModeType { LongMode_Enabled, LongMode_Disabled, LongMode_Legacy } LongModeType;
LongModeType enmLongMode;
uint32_t cCPUs;
diff --git a/include/VBox/shflsvc.h b/include/VBox/shflsvc.h
index eb34789..fdcd5c3 100644
--- a/include/VBox/shflsvc.h
+++ b/include/VBox/shflsvc.h
@@ -483,6 +483,8 @@ DECLINLINE(void) vbfsCopyFsObjInfoFromIprt(PSHFLFSOBJINFO pDst, PCRTFSOBJINFO pS
pDst->ChangeTime = pSrc->ChangeTime;
pDst->BirthTime = pSrc->BirthTime;
pDst->Attr.fMode = pSrc->Attr.fMode;
+ /* Clear bits which we don't pass through for security reasons. */
+ pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
RT_ZERO(pDst->Attr.u);
switch (pSrc->Attr.enmAdditional)
{
diff --git a/include/VBox/sup.h b/include/VBox/sup.h
index bf9f299..fba748a 100644
--- a/include/VBox/sup.h
+++ b/include/VBox/sup.h
@@ -1907,6 +1907,7 @@ SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3);
SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip);
SUPR0DECL(int) SUPR0GetSvmUsability(bool fInitSvm);
SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous);
+SUPR0DECL(int) SUPR0GetRawModeUsability(void);
SUPR0DECL(int) SUPR0GetCurrentGdtRw(RTHCUINTPTR *pGdtRw);
SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps);
SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession);
diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h
index f80dd28..cf15790 100644
--- a/include/VBox/vmm/cpum.h
+++ b/include/VBox/vmm/cpum.h
@@ -73,6 +73,8 @@ typedef enum CPUMCPUIDFEATURE
CPUMCPUIDFEATURE_HVP,
/** The MWait Extensions bits (Std) */
CPUMCPUIDFEATURE_MWAIT_EXTS,
+ /** The speculation control feature bits. (StExt) */
+ CPUMCPUIDFEATURE_SPEC_CTRL,
/** 32bit hackishness. */
CPUMCPUIDFEATURE_32BIT_HACK = 0x7fffffff
} CPUMCPUIDFEATURE;
@@ -469,6 +471,8 @@ typedef enum CPUMMSRRDFN
kCpumMsrRdFn_Ia32VmxTrueExitCtls, /**< Takes real value as reference. */
kCpumMsrRdFn_Ia32VmxTrueEntryCtls, /**< Takes real value as reference. */
kCpumMsrRdFn_Ia32VmxVmFunc, /**< Takes real value as reference. */
+ kCpumMsrRdFn_Ia32SpecCtrl,
+ kCpumMsrRdFn_Ia32ArchCapabilities,
kCpumMsrRdFn_Amd64Efer,
kCpumMsrRdFn_Amd64SyscallTarget,
@@ -721,6 +725,8 @@ typedef enum CPUMMSRWRFN
kCpumMsrWrFn_Ia32TscDeadline,
kCpumMsrWrFn_Ia32X2ApicN,
kCpumMsrWrFn_Ia32DebugInterface,
+ kCpumMsrWrFn_Ia32SpecCtrl,
+ kCpumMsrWrFn_Ia32PredCmd,
kCpumMsrWrFn_Amd64Efer,
kCpumMsrWrFn_Amd64SyscallTarget,
@@ -1033,6 +1039,12 @@ typedef struct CPUMFEATURES
uint32_t fStibp : 1;
/** Supports IA32_ARCH_CAP. */
uint32_t fArchCap : 1;
+ /** Supports PCID. */
+ uint32_t fPcid : 1;
+ /** Supports INVPCID. */
+ uint32_t fInvpcid : 1;
+ /** Supports read/write FSGSBASE instructions. */
+ uint32_t fFsGsBase : 1;
/** Supports AMD 3DNow instructions. */
uint32_t f3DNow : 1;
@@ -1065,8 +1077,13 @@ typedef struct CPUMFEATURES
/** Support for Intel VMX. */
uint32_t fVmx : 1;
+ /** Indicates that speculative execution control CPUID bits and
+ * MSRs are exposed. The details are different for Intel and
+ * AMD but both have similar functionality. */
+ uint32_t fSpeculationControl : 1;
+
/** Alignment padding / reserved for future use. */
- uint32_t fPadding : 19;
+ uint32_t fPadding : 15;
/** SVM: Supports Nested-paging. */
uint32_t fSvmNestedPaging : 1;
@@ -1201,6 +1218,8 @@ VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenCsAndSs(PVMCPU pVCpu);
VMM_INT_DECL(void) CPUMGuestLazyLoadHiddenSelectorReg(PVMCPU pVCpu, PCPUMSELREG pSReg);
VMMR0_INT_DECL(void) CPUMR0SetGuestTscAux(PVMCPU pVCpu, uint64_t uValue);
VMMR0_INT_DECL(uint64_t) CPUMR0GetGuestTscAux(PVMCPU pVCpu);
+VMMR0_INT_DECL(void) CPUMR0SetGuestSpecCtrl(PVMCPU pVCpu, uint64_t uValue);
+VMMR0_INT_DECL(uint64_t) CPUMR0GetGuestSpecCtrl(PVMCPU pVCpu);
/** @} */
diff --git a/include/VBox/vmm/cpumctx.h b/include/VBox/vmm/cpumctx.h
index 61d2394..6f03250 100644
--- a/include/VBox/vmm/cpumctx.h
+++ b/include/VBox/vmm/cpumctx.h
@@ -777,6 +777,8 @@ typedef union CPUMCTXMSRS
uint64_t MtrrFix4K_F0000; /**< IA32_MTRR_FIX4K_F0000 */
uint64_t MtrrFix4K_F8000; /**< IA32_MTRR_FIX4K_F8000 */
uint64_t PkgCStateCfgCtrl; /**< MSR_PKG_CST_CONFIG_CONTROL */
+ uint64_t SpecCtrl; /**< IA32_SPEC_CTRL */
+ uint64_t ArchCaps; /**< IA32_ARCH_CAPABILITIES */
} msr;
uint64_t au64[64];
} CPUMCTXMSRS;
diff --git a/include/VBox/vmm/iem.h b/include/VBox/vmm/iem.h
index f33f21d..cdb79f6 100644
--- a/include/VBox/vmm/iem.h
+++ b/include/VBox/vmm/iem.h
@@ -216,6 +216,7 @@ VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClts(PVMCPU pVCpu, uint8_t cbInstr);
VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedLmsw(PVMCPU pVCpu, uint8_t cbInstr, uint16_t uValue);
VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedXsetbv(PVMCPU pVCpu, uint8_t cbInstr);
VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpg(PVMCPU pVCpu, uint8_t cbInstr, RTGCPTR GCPtrPage);
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvpcid(PVMCPU pVCpu, uint8_t cbInstr, uint8_t uType, RTGCPTR GCPtrInvpcidDesc);
#ifdef VBOX_WITH_NESTED_HWVIRT
VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClgi(PVMCPU pVCpu, uint8_t cbInstr);
VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedStgi(PVMCPU pVCpu, uint8_t cbInstr);
diff --git a/include/VBox/vmm/pdmstorageifs.h b/include/VBox/vmm/pdmstorageifs.h
index db42f6b..7bf5ba3 100644
--- a/include/VBox/vmm/pdmstorageifs.h
+++ b/include/VBox/vmm/pdmstorageifs.h
@@ -226,9 +226,29 @@ typedef struct PDMIMEDIAPORT
DECLR3CALLBACKMEMBER(int, pfnQueryDeviceLocation, (PPDMIMEDIAPORT pInterface, const char **ppcszController,
uint32_t *piInstance, uint32_t *piLUN));
+
+ /**
+ * Queries the vendor and product ID and revision to report for INQUIRY commands in underlying devices.
+ *
+ * @returns VBox status code.
+ * @param pInterface Pointer to this interface.
+ * @param ppszVendorId Where to store the pointer to the vendor ID string to report.
+ * @param ppszProductId Where to store the pointer to the product ID string to report.
+ * @param ppszRevision Where to store the pointer to the revision string to report.
+ *
+ * @note The strings for the inquiry data are stored in the storage controller rather than in the device
+ * because if device attachments change (virtual CD/DVD drive versus host drive) there is currently no
+ * way to keep the INQUIRY data in extradata keys without causing trouble when the attachment is changed.
+ * Also Main currently doesn't has any settings for the attachment to store such information in the settings
+ * properly. Last reason (but not the most important one) is to stay compatible with older versions
+ * where the drive emulation was in AHCI but it now uses VSCSI and the settings overwrite should still work.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnQueryScsiInqStrings, (PPDMIMEDIAPORT pInterface, const char **ppszVendorId,
+ const char **ppszProductId, const char **ppszRevision));
+
} PDMIMEDIAPORT;
/** PDMIMEDIAPORT interface ID. */
-#define PDMIMEDIAPORT_IID "9f7e8c9e-6d35-4453-bbef-1f78033174d6"
+#define PDMIMEDIAPORT_IID "77180ab8-6485-454f-b440-efca322b7bd7"
/** Pointer to a media interface. */
typedef struct PDMIMEDIA *PPDMIMEDIA;
diff --git a/include/VBox/vscsi.h b/include/VBox/vscsi.h
index ced4a8b..168819b 100644
--- a/include/VBox/vscsi.h
+++ b/include/VBox/vscsi.h
@@ -245,6 +245,21 @@ typedef struct VSCSILUNIOCALLBACKS
*/
DECLR3CALLBACKMEMBER(int, pfnVScsiLunGetFeatureFlags,(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pfFeatures));
+ /**
+ * Queries the vendor and product ID and revision to report for INQUIRY commands of the given LUN.
+ *
+ * @returns VBox status status code.
+ * @retval VERR_NOT_FOUND if the data is not available and some defaults should be sued instead.
+ * @param hVScsiLun Virtual SCSI LUN handle.
+ * @param pvScsiLunUser Opaque user data which may be used to identify the
+ * medium.
+ * @param ppszVendorId Where to store the pointer to the vendor ID string to report.
+ * @param ppszProductId Where to store the pointer to the product ID string to report.
+ * @param ppszProductLevel Where to store the pointer to the product level string to report.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnVScsiLunQueryInqStrings, (VSCSILUN hVScsiLun, void *pvScsiLunUser, const char **ppszVendorId,
+ const char **ppszProductId, const char **ppszProductLevel));
+
} VSCSILUNIOCALLBACKS;
/** Pointer to a virtual SCSI LUN I/O callback table. */
typedef VSCSILUNIOCALLBACKS *PVSCSILUNIOCALLBACKS;
diff --git a/include/iprt/linux/symvers.h b/include/iprt/linux/symvers.h
new file mode 100644
index 0000000..78e2421
--- /dev/null
+++ b/include/iprt/linux/symvers.h
@@ -0,0 +1,58 @@
+/* $Id: symvers.h $ */
+/** @file
+ * IPRT - Linux symver and compatibility definitions.
+ */
+
+/*
+ * Copyright (C) 2008-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+/* Various tricks to produce binaries which can be run on old Linux
+ * distributions. This will almost certainly need updating as time
+ * goes by. */
+
+#ifndef ___iprt_linux_symvers_h
+#define ___iprt_linux_symvers_h
+
+/* Please use -fno-stack-protector on the command line to avoid stack check
+ * functions which are not available in EL3 for 32-bit builds. */
+
+/* Use versions of glibc symbols which are available in 32-bit EL3 or
+ * 64-bit EL4. Currently only those symbols needed by the Additions,
+ * though this could probably be extended to work for host builds too. */
+#if defined(RT_ARCH_AMD64)
+__asm__(".symver memcpy,memcpy at GLIBC_2.2.5");
+__asm__(".symver posix_spawn,posix_spawn at GLIBC_2.2.5");
+#else /* RT_ARCH_X86 */
+__asm__(".symver posix_spawn,posix_spawn at GLIBC_2.2");
+#endif
+
+/* Do not use *_chk functions */
+#undef _FORTIFY_SOURCE
+
+/* Do not use __isoc99_* functions */
+#undef __USE_GNU
+#define __USE_GNU 1
+
+/* Tell IPRT not to use newer functions */
+#include <features.h>
+#undef __GLIBC_MINOR__
+#define __GLIBC_MINOR__ 3
+#endif /* ___iprt_linux_symvers_h */
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
index 50d63db..e7aef73 100644
--- a/include/iprt/mangling.h
+++ b/include/iprt/mangling.h
@@ -2223,6 +2223,7 @@
# define RTThreadWait RT_MANGLER(RTThreadWait)
# define RTThreadWaitNoResume RT_MANGLER(RTThreadWaitNoResume)
# define RTThreadYield RT_MANGLER(RTThreadYield)
+# define RTTimeCompare RT_MANGLER(RTTimeCompare)
# define RTTimeDbgBad RT_MANGLER(RTTimeDbgBad)
# define RTTimeDbgExpired RT_MANGLER(RTTimeDbgExpired)
# define RTTimeDbgRaces RT_MANGLER(RTTimeDbgRaces)
diff --git a/include/iprt/time.h b/include/iprt/time.h
index 1b5e714..0728a30 100644
--- a/include/iprt/time.h
+++ b/include/iprt/time.h
@@ -786,6 +786,21 @@ RTDECL(PRTTIME) RTTimeFromString(PRTTIME pTime, const char *pszString);
RTDECL(bool) RTTimeIsLeapYear(int32_t i32Year);
/**
+ * Compares two normalized time structures.
+ *
+ * @retval 0 if equal.
+ * @retval -1 if @a pLeft is earlier than @a pRight.
+ * @retval 1 if @a pRight is earlier than @a pLeft.
+ *
+ * @param pLeft The left side time. NULL is accepted.
+ * @param pRight The right side time. NULL is accepted.
+ *
+ * @note A NULL time is considered smaller than anything else. If both are
+ * NULL, they are considered equal.
+ */
+RTDECL(int) RTTimeCompare(PCRTTIME pLeft, PCRTTIME pRight);
+
+/**
* Gets the current nanosecond timestamp.
*
* @returns nanosecond timestamp.
diff --git a/include/iprt/x86.h b/include/iprt/x86.h
index 8e00242..86c81b1 100644
--- a/include/iprt/x86.h
+++ b/include/iprt/x86.h
@@ -616,7 +616,7 @@ typedef const X86CPUIDFEATEDX *PCX86CPUIDFEATEDX;
/** EDX Bit 27 - IBRS & IBPB - Supports the STIBP flag in IA32_SPEC_CTRL. */
#define X86_CPUID_STEXT_FEATURE_EDX_STIBP RT_BIT_32(27)
-/** EDX Bit 29 - ARCHCAP - Supports the IA32_ARCH_CAP MSR. */
+/** EDX Bit 29 - ARCHCAP - Supports the IA32_ARCH_CAPABILITIES MSR. */
#define X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT_32(29)
/** @} */
@@ -897,6 +897,8 @@ typedef const X86CPUIDFEATEDX *PCX86CPUIDFEATEDX;
#define X86_CR4_VMXE RT_BIT_32(13)
/** Bit 14 - SMXE - Safer Mode Extensions Enabled. */
#define X86_CR4_SMXE RT_BIT_32(14)
+/** Bit 16 - FSGSBASE - Read/write FSGSBASE instructions Enable. */
+#define X86_CR4_FSGSBASE RT_BIT_32(16)
/** Bit 17 - PCIDE - Process-Context Identifiers Enabled. */
#define X86_CR4_PCIDE RT_BIT_32(17)
/** Bit 18 - OSXSAVE - Operating System Support for XSAVE and processor
@@ -1202,7 +1204,7 @@ AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00040000)) == 0);
/** Architecture capabilities (bugfixes).
* @note May move */
-#define MSR_IA32_ARCH_CAP UINT32_C(0x10a)
+#define MSR_IA32_ARCH_CAPABILITIES UINT32_C(0x10a)
/** CPU is no subject to spectre problems. */
#define MSR_IA32_ARCH_CAP_F_SPECTRE_FIX RT_BIT_32(0)
/** CPU has better IBRS and you can leave it on all the time. */
@@ -2585,6 +2587,20 @@ typedef const X86PML4 *PCX86PML4;
/** @} */
/**
+ * Intel PCID invalidation types.
+ */
+/** Individual address invalidation. */
+#define X86_INVPCID_TYPE_INDV_ADDR 0
+/** Single-context invalidation. */
+#define X86_INVPCID_TYPE_SINGLE_CONTEXT 1
+/** All-context including globals invalidation. */
+#define X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL 2
+/** All-context excluding globals invalidation. */
+#define X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL 3
+/** The maximum valid invalidation type value. */
+#define X86_INVPCID_TYPE_MAX_VALID X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL
+
+/**
* 32-bit protected mode FSTENV image.
*/
typedef struct X86FSTENV32P
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
index 9141ed3..8236bcf 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
@@ -1,4 +1,4 @@
-/* $Rev: 118839 $ */
+/* $Rev: 120349 $ */
/** @file
* VBoxGuest - Linux specifics.
*
@@ -39,6 +39,12 @@
# define VBOXGUEST_WITH_INPUT_DRIVER
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+# define CONST_4_15 const
+#else
+# define CONST_4_15
+#endif
+
#include "VBoxGuestInternal.h"
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
# include <linux/input.h>
@@ -1058,7 +1064,7 @@ void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
/** log and dbg_log parameter setter. */
-static int vgdrvLinuxParamLogGrpSet(const char *pszValue, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogGrpSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
{
if (g_fLoggerCreated)
{
@@ -1073,7 +1079,7 @@ static int vgdrvLinuxParamLogGrpSet(const char *pszValue, struct kernel_param *p
}
/** log and dbg_log parameter getter. */
-static int vgdrvLinuxParamLogGrpGet(char *pszBuf, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogGrpGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
{
PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
*pszBuf = '\0';
@@ -1084,7 +1090,7 @@ static int vgdrvLinuxParamLogGrpGet(char *pszBuf, struct kernel_param *pParam)
/** log and dbg_log_flags parameter setter. */
-static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
{
if (g_fLoggerCreated)
{
@@ -1098,7 +1104,7 @@ static int vgdrvLinuxParamLogFlagsSet(const char *pszValue, struct kernel_param
}
/** log and dbg_log_flags parameter getter. */
-static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
{
PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
*pszBuf = '\0';
@@ -1109,7 +1115,7 @@ static int vgdrvLinuxParamLogFlagsGet(char *pszBuf, struct kernel_param *pParam)
/** log and dbg_log_dest parameter setter. */
-static int vgdrvLinuxParamLogDstSet(const char *pszValue, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogDstSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
{
if (g_fLoggerCreated)
{
@@ -1123,7 +1129,7 @@ static int vgdrvLinuxParamLogDstSet(const char *pszValue, struct kernel_param *p
}
/** log and dbg_log_dest parameter getter. */
-static int vgdrvLinuxParamLogDstGet(char *pszBuf, struct kernel_param *pParam)
+static int vgdrvLinuxParamLogDstGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
{
PRTLOGGER pLogger = pParam->name[0] == 'd' ? RTLogDefaultInstance() : RTLogRelGetDefaultInstance();
*pszBuf = '\0';
@@ -1134,7 +1140,7 @@ static int vgdrvLinuxParamLogDstGet(char *pszBuf, struct kernel_param *pParam)
/** r3_log_to_host parameter setter. */
-static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, struct kernel_param *pParam)
+static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, CONST_4_15 struct kernel_param *pParam)
{
if ( pszValue == NULL
|| *pszValue == '\0'
@@ -1152,7 +1158,7 @@ static int vgdrvLinuxParamR3LogToHostSet(const char *pszValue, struct kernel_par
}
/** r3_log_to_host parameter getter. */
-static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf, struct kernel_param *pParam)
+static int vgdrvLinuxParamR3LogToHostGet(char *pszBuf, CONST_4_15 struct kernel_param *pParam)
{
strcpy(pszBuf, g_DevExt.fLoggingEnabled ? "enabled" : "disabled");
return strlen(pszBuf);
diff --git a/src/VBox/Additions/common/crOpenGL/entrypoints.pyc b/src/VBox/Additions/common/crOpenGL/entrypoints.pyc
index 45a998e..f5110dc 100644
Binary files a/src/VBox/Additions/common/crOpenGL/entrypoints.pyc and b/src/VBox/Additions/common/crOpenGL/entrypoints.pyc differ
diff --git a/src/VBox/Additions/linux/drm/vbox_mode.c b/src/VBox/Additions/linux/drm/vbox_mode.c
index 018a386..8e33a11 100644
--- a/src/VBox/Additions/linux/drm/vbox_mode.c
+++ b/src/VBox/Additions/linux/drm/vbox_mode.c
@@ -401,7 +401,11 @@ static struct drm_encoder *vbox_best_single_encoder(struct drm_connector
/* pick the encoder ids */
if (enc_id)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
+ return drm_encoder_find(connector->dev, NULL, enc_id);
+#else
return drm_encoder_find(connector->dev, enc_id);
+#endif
return NULL;
}
diff --git a/src/VBox/Additions/linux/installer/install.sh.in b/src/VBox/Additions/linux/installer/install.sh.in
index 391be9a..4221a27 100755
--- a/src/VBox/Additions/linux/installer/install.sh.in
+++ b/src/VBox/Additions/linux/installer/install.sh.in
@@ -51,6 +51,8 @@ MODULES_STOPPED=1
check_root
+check_deps bzip2 tar
+
create_log "$LOGFILE"
## @todo r=andy: Explain options like "force" and "no_setup" -- not self-explanatory
diff --git a/src/VBox/Additions/linux/installer/vboxadd-x11.sh b/src/VBox/Additions/linux/installer/vboxadd-x11.sh
index 1bab70d..52a9c4e 100755
--- a/src/VBox/Additions/linux/installer/vboxadd-x11.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd-x11.sh
@@ -1,7 +1,7 @@
#! /bin/sh
# $Id: vboxadd-x11.sh $
## @file
-# Linux Additions X11 setup init script ($Revision: 118839 $)
+# Linux Additions X11 setup init script ($Revision: 120778 $)
#
#
@@ -332,7 +332,7 @@ setup()
autokeyboard=""
case $x_version in
6.8.* )
- autokeyboard="true"
+ autokeyboard="--autoKeyboard"
;;
4.2.* | 4.3.* )
main_cfg="/etc/X11/XF86Config"
@@ -550,6 +550,7 @@ EOF
# Remove other files
rm /usr/share/xserver-xorg/pci/vboxvideo.ids 2>/dev/null
+ return 0
}
dmnstatus()
diff --git a/src/VBox/Additions/linux/installer/vboxadd.sh b/src/VBox/Additions/linux/installer/vboxadd.sh
index 3d4a6d1..f1a7b73 100755
--- a/src/VBox/Additions/linux/installer/vboxadd.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd.sh
@@ -1,7 +1,7 @@
#! /bin/sh
# $Id: vboxadd.sh $
## @file
-# Linux Additions kernel module init script ($Revision: 120119 $)
+# Linux Additions kernel module init script ($Revision: 120325 $)
#
#
@@ -128,12 +128,11 @@ log()
echo "${1}" >> "${LOG}"
}
-dev=vboxguest
-userdev=vboxuser
+dev=/dev/vboxguest
+userdev=/dev/vboxuser
config=/var/lib/VBoxGuestAdditions/config
owner=vboxadd
group=1
-usergroup=vboxadd
if test -r $config; then
. $config
@@ -165,7 +164,7 @@ running_vboxvideo()
do_vboxguest_non_udev()
{
- if [ ! -c /dev/$dev ]; then
+ if [ ! -c $dev ]; then
maj=`sed -n 's;\([0-9]\+\) vboxguest;\1;p' /proc/devices`
if [ ! -z "$maj" ]; then
min=0
@@ -180,32 +179,32 @@ do_vboxguest_non_udev()
fail "Cannot locate the VirtualBox device"
}
- mknod -m 0660 /dev/$dev c $maj $min || {
+ mknod -m 0664 $dev c $maj $min || {
rmmod vboxguest 2>/dev/null
- fail "Cannot create device /dev/$dev with major $maj and minor $min"
+ fail "Cannot create device $dev with major $maj and minor $min"
}
fi
- chown $owner:$group /dev/$dev 2>/dev/null || {
- rm -f /dev/$dev 2>/dev/null
- rm -f /dev/$userdev 2>/dev/null
+ chown $owner:$group $dev 2>/dev/null || {
+ rm -f $dev 2>/dev/null
+ rm -f $userdev 2>/dev/null
rmmod vboxguest 2>/dev/null
- fail "Cannot change owner $owner:$group for device /dev/$dev"
+ fail "Cannot change owner $owner:$group for device $dev"
}
- if [ ! -c /dev/$userdev ]; then
+ if [ ! -c $userdev ]; then
maj=10
min=`sed -n 's;\([0-9]\+\) vboxuser;\1;p' /proc/misc`
if [ ! -z "$min" ]; then
- mknod -m 0660 /dev/$userdev c $maj $min || {
- rm -f /dev/$dev 2>/dev/null
+ mknod -m 0666 $userdev c $maj $min || {
+ rm -f $dev 2>/dev/null
rmmod vboxguest 2>/dev/null
- fail "Cannot create device /dev/$userdev with major $maj and minor $min"
+ fail "Cannot create device $userdev with major $maj and minor $min"
}
- chown $owner:$usergroup /dev/$userdev 2>/dev/null || {
- rm -f /dev/$dev 2>/dev/null
- rm -f /dev/$userdev 2>/dev/null
+ chown $owner:$group $userdev 2>/dev/null || {
+ rm -f $dev 2>/dev/null
+ rm -f $userdev 2>/dev/null
rmmod vboxguest 2>/dev/null
- fail "Cannot change owner $owner:$usergroup for device /dev/$userdev"
+ fail "Cannot change owner $owner:$group for device $userdev"
}
fi
fi
@@ -221,12 +220,12 @@ start()
ps -A -o comm | grep -q '/*udevd$' 2>/dev/null ||
no_udev=1
running_vboxguest || {
- rm -f /dev/$dev || {
- fail "Cannot remove /dev/$dev"
+ rm -f $dev || {
+ fail "Cannot remove $dev"
}
- rm -f /dev/$userdev || {
- fail "Cannot remove /dev/$userdev"
+ rm -f $userdev || {
+ fail "Cannot remove $userdev"
}
$MODPROBE vboxguest >/dev/null 2>&1 || {
@@ -370,14 +369,10 @@ create_vbox_user()
log "Creating user for the Guest Additions."
# This is the LSB version of useradd and should work on recent
# distributions
- useradd -d /var/run/"${owner}" -g 1 -r -s /bin/false "${owner}" >/dev/null 2>&1
+ useradd -d /var/run/vboxadd -g 1 -r -s /bin/false vboxadd >/dev/null 2>&1
# And for the others, we choose a UID ourselves
- useradd -d /var/run/"${owner}" -g 1 -u 501 -o -s /bin/false "${owner}" >/dev/null 2>&1
- # And create the group for the user device:
- groupadd "${usergroup}"
- # VBoxClient needs to be setgid.
- chown :"${usergroup}" "${INSTALL_DIR}/bin/VBoxClient"
- chmod g+s "${INSTALL_DIR}/bin/VBoxClient"
+ useradd -d /var/run/vboxadd -g 1 -u 501 -o -s /bin/false vboxadd >/dev/null 2>&1
+
}
create_udev_rule()
@@ -404,8 +399,8 @@ create_udev_rule()
fi
fi
## @todo 60-vboxadd.rules -> 60-vboxguest.rules ?
- echo "KERNEL=${udev_fix}\"vboxguest\", NAME=\"${dev}\", OWNER=\"${owner}\", MODE=\"0660\"" > /etc/udev/rules.d/60-vboxadd.rules
- echo "KERNEL=${udev_fix}\"vboxuser\", NAME=\"${userdev}\", OWNER=\"${owner}\", GROUP=\"${usergroup}\", MODE=\"0660\"" >> /etc/udev/rules.d/60-vboxadd.rules
+ echo "KERNEL=${udev_fix}\"vboxguest\", NAME=\"vboxguest\", OWNER=\"vboxadd\", MODE=\"0660\"" > /etc/udev/rules.d/60-vboxadd.rules
+ echo "KERNEL=${udev_fix}\"vboxuser\", NAME=\"vboxuser\", OWNER=\"vboxadd\", MODE=\"0666\"" >> /etc/udev/rules.d/60-vboxadd.rules
fi
}
diff --git a/src/VBox/Additions/linux/sharedfolders/utils.c b/src/VBox/Additions/linux/sharedfolders/utils.c
index 749205a..187ba2e 100644
--- a/src/VBox/Additions/linux/sharedfolders/utils.c
+++ b/src/VBox/Additions/linux/sharedfolders/utils.c
@@ -79,10 +79,7 @@ void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
attr = &info->Attr;
#define mode_set(r) attr->fMode & (RTFS_UNIX_##r) ? (S_##r) : 0;
- mode = mode_set(ISUID);
- mode |= mode_set(ISGID);
-
- mode |= mode_set(IRUSR);
+ mode = mode_set(IRUSR);
mode |= mode_set(IWUSR);
mode |= mode_set(IXUSR);
@@ -360,9 +357,7 @@ int sf_setattr(struct dentry *dentry, struct iattr *iattr)
RT_ZERO(info);
if (iattr->ia_valid & ATTR_MODE)
{
- info.Attr.fMode = mode_set(ISUID);
- info.Attr.fMode |= mode_set(ISGID);
- info.Attr.fMode |= mode_set(IRUSR);
+ info.Attr.fMode = mode_set(IRUSR);
info.Attr.fMode |= mode_set(IWUSR);
info.Attr.fMode |= mode_set(IXUSR);
info.Attr.fMode |= mode_set(IRGRP);
diff --git a/src/VBox/Additions/x11/VBoxClient/Makefile.kmk b/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
index 5d4a9ee..487f888 100644
--- a/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
+++ b/src/VBox/Additions/x11/VBoxClient/Makefile.kmk
@@ -66,6 +66,21 @@ endif
VBoxClient_LIBS += \
supc++ \
gcc_eh
+ifdef VBOX_WITH_OLD_GLIBC_SUPPORT
+ # This has to be in LIBS, so as to be linked in after supc++ and gcc_eh, which
+ # depend on the symbols it provides. Static supc++ and gcc_eh on at least
+ # Ubuntu 17.04 contain references to __sprintf_chk and __stack_chk_fail.
+ # Furthermore, they contain references to memcpy, which needs to be resolved
+ # to memcpy at GLIBC_2.2.5, which we solve in a not-very-satisfactory way with a
+ # wrapper.
+ ifeq ($(KBUILD_TARGET),linux)
+VBoxClient_LIBS += \
+ $(PATH_ROOT)/src/VBox/Additions/x11/VBoxClient/chk_stubs.c
+VBoxClient_LDFLAGS.amd64 += \
+ -Wl,--wrap=memcpy
+ endif
+endif
+
ifdef VBOX_X11_SEAMLESS_GUEST
VBoxClient_DEFS += SEAMLESS_GUEST DYNAMIC_RESIZE
VBoxClient_SOURCES += \
diff --git a/src/VBox/Additions/x11/VBoxClient/chk_stubs.c b/src/VBox/Additions/x11/VBoxClient/chk_stubs.c
new file mode 100644
index 0000000..2357a2c
--- /dev/null
+++ b/src/VBox/Additions/x11/VBoxClient/chk_stubs.c
@@ -0,0 +1,56 @@
+/* $Id: chk_stubs.c $ */
+/** @file
+ * glibc stubs for the VirtualBox Guest Addition X11 Client.
+ */
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+/* If we want the binary to be usable with glibc 2.3, we have to prevent
+ VBoxClient from containing later symbols. This includes resolution of
+ symbols from supc++ and gcc_eh. */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+extern int __sprintf_chk(char *psz, int fFlags, size_t cb, const char *pszFormat, ...);
+int __sprintf_chk(char *psz, int fFlags, size_t cb, const char *pszFormat, ...)
+{
+ int rc;
+ va_list va;
+
+ (void)fFlags;
+ va_start(va, pszFormat);
+ rc = vsnprintf(psz, cb, pszFormat, va);
+ va_end(va);
+ return rc;
+}
+
+extern void __stack_chk_fail(void);
+void __stack_chk_fail(void)
+{
+ fprintf(stderr, "Stack check failed!\n");
+ _exit(1);
+}
+
+#ifdef __x86_64
+/* Furthermore, wrap references to memcpy to force them to go to the right
+ * version. We are forced to do it this way because the shared libraries
+ * supc++ and gcc_eh contain references which we cannot change. */
+asm (".symver memcpy, memcpy at GLIBC_2.2.5");
+void *__wrap_memcpy(void *dest, const void *src, size_t n)
+{
+ return memcpy(dest, src, n);
+}
+#endif
diff --git a/src/VBox/Devices/Audio/AudioMixBuffer.cpp b/src/VBox/Devices/Audio/AudioMixBuffer.cpp
index b670647..fc57d7e 100644
--- a/src/VBox/Devices/Audio/AudioMixBuffer.cpp
+++ b/src/VBox/Devices/Audio/AudioMixBuffer.cpp
@@ -1519,11 +1519,11 @@ int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
* @param pMixBuf Mixing buffer to read audio frames from.
* @param pvBuf Pointer to buffer to write output to.
* @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcRead Number of audio frames read. Optional.
+ * @param pcBlock Returns acquired block to read (in audio frames).
*/
-int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+int AudioMixBufAcquireReadBlock(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcBlock)
{
- return AudioMixBufReadCircEx(pMixBuf, pMixBuf->AudioFmt, pvBuf, cbBuf, pcRead);
+ return AudioMixBufAcquireReadBlockEx(pMixBuf, pMixBuf->AudioFmt, pvBuf, cbBuf, pcBlock);
}
/**
@@ -1536,14 +1536,15 @@ int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, ui
* @param enmFmt Audio format to use for output.
* @param pvBuf Pointer to buffer to write output to.
* @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcRead Number of audio frames read. Optional.
+ * @param pcBlock Returns acquired block to read (in audio frames).
*/
-int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+int AudioMixBufAcquireReadBlockEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf,
+ uint32_t *pcBlock)
{
AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcRead is optional. */
+ AssertPtrReturn(pcBlock, VERR_INVALID_POINTER);
/* Make sure that we at least have space for a full audio frame. */
AssertReturn(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), VERR_INVALID_PARAMETER);
@@ -1558,8 +1559,7 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
#ifdef DEBUG
audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
#endif
- if (pcRead)
- *pcRead = 0;
+ *pcBlock = 0;
return VINF_SUCCESS;
}
@@ -1596,13 +1596,9 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
RTFileClose(fh);
}
#endif
- pMixBuf->offRead = (pMixBuf->offRead + cToRead) % pMixBuf->cFrames;
- Assert(pMixBuf->cUsed >= cToRead);
- pMixBuf->cUsed -= cToRead;
}
- if (pcRead)
- *pcRead = cToRead;
+ *pcBlock = cToRead;
#ifdef DEBUG
audioMixBufDbgValidate(pMixBuf);
@@ -1613,6 +1609,24 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
}
/**
+ * Releases a formerly acquired read block again.
+ *
+ * @param pMixBuf Mixing buffer to release acquired read block for.
+ * @param cBlock Size of the block to release (in audio frames).
+ */
+void AudioMixBufReleaseReadBlock(PPDMAUDIOMIXBUF pMixBuf, uint32_t cBlock)
+{
+ AssertPtrReturnVoid(pMixBuf);
+
+ if (!cBlock)
+ return;
+
+ pMixBuf->offRead = (pMixBuf->offRead + cBlock) % pMixBuf->cFrames;
+ Assert(pMixBuf->cUsed >= cBlock);
+ pMixBuf->cUsed -= RT_MIN(cBlock, pMixBuf->cUsed);
+}
+
+/**
* Returns the current read position of a mixing buffer.
*
* @returns IPRT status code.
diff --git a/src/VBox/Devices/Audio/AudioMixBuffer.h b/src/VBox/Devices/Audio/AudioMixBuffer.h
index 3af6256..72a5c7d 100644
--- a/src/VBox/Devices/Audio/AudioMixBuffer.h
+++ b/src/VBox/Devices/Audio/AudioMixBuffer.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2017 Oracle Corporation
+ * Copyright (C) 2014-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -65,8 +65,9 @@ int AudioMixBufPeekMutable(PPDMAUDIOMIXBUF pMixBuf, uint32_t cFramesToRead, PPDM
uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf);
int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
-int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
-int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
+int AudioMixBufAcquireReadBlock(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcBlock);
+int AudioMixBufAcquireReadBlockEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcBlock);
+void AudioMixBufReleaseReadBlock(PPDMAUDIOMIXBUF pMixBuf, uint32_t cBlock);
uint32_t AudioMixBufReadPos(PPDMAUDIOMIXBUF pMixBuf);
void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf);
void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol);
diff --git a/src/VBox/Devices/Audio/DevHDA.cpp b/src/VBox/Devices/Audio/DevHDA.cpp
index 8dac716..caeb2a7 100644
--- a/src/VBox/Devices/Audio/DevHDA.cpp
+++ b/src/VBox/Devices/Audio/DevHDA.cpp
@@ -8,7 +8,7 @@
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -271,21 +271,14 @@ static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
* @{
*/
#ifdef IN_RING3
+static int hdaAddStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg);
+static int hdaRemoveStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg);
# ifdef HDA_USE_DMA_ACCESS_HANDLER
static DECLCALLBACK(VBOXSTRICTRC) hdaDMAAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser);
# endif
-static void hdaDoTransfers(PHDASTATE pThis);
#endif /* IN_RING3 */
/** @} */
-/** @name Timer functions.
- * @{
- */
-#ifdef IN_RING3
-static void hdaTimerMain(PHDASTATE pThis);
-#endif
-/** @} */
-
/*********************************************************************************************************************************
* Global Variables *
@@ -501,9 +494,9 @@ static uint32_t const g_afMasks[5] =
/**
* Acquires the TM lock and HDA lock, returns on failure.
*/
-#define DEVHDA_LOCK_BOTH_RETURN_VOID(a_pThis) \
+#define DEVHDA_LOCK_BOTH_RETURN_VOID(a_pThis, a_SD) \
do { \
- int rcLock = TMTimerLock((a_pThis)->pTimer, VERR_IGNORED); \
+ int rcLock = TMTimerLock((a_pThis)->pTimer[a_SD], VERR_IGNORED); \
if (rcLock != VINF_SUCCESS) \
{ \
AssertRC(rcLock); \
@@ -513,7 +506,7 @@ static uint32_t const g_afMasks[5] =
if (rcLock != VINF_SUCCESS) \
{ \
AssertRC(rcLock); \
- TMTimerUnlock((a_pThis)->pTimer); \
+ TMTimerUnlock((a_pThis)->pTimer[a_SD]); \
return; \
} \
} while (0)
@@ -521,16 +514,16 @@ static uint32_t const g_afMasks[5] =
/**
* Acquires the TM lock and HDA lock, returns on failure.
*/
-#define DEVHDA_LOCK_BOTH_RETURN(a_pThis, a_rcBusy) \
+#define DEVHDA_LOCK_BOTH_RETURN(a_pThis, a_SD, a_rcBusy) \
do { \
- int rcLock = TMTimerLock((a_pThis)->pTimer, (a_rcBusy)); \
+ int rcLock = TMTimerLock((a_pThis)->pTimer[a_SD], (a_rcBusy)); \
if (rcLock != VINF_SUCCESS) \
return rcLock; \
rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, (a_rcBusy)); \
if (rcLock != VINF_SUCCESS) \
{ \
AssertRC(rcLock); \
- TMTimerUnlock((a_pThis)->pTimer); \
+ TMTimerUnlock((a_pThis)->pTimer[a_SD]); \
return rcLock; \
} \
} while (0)
@@ -538,10 +531,10 @@ static uint32_t const g_afMasks[5] =
/**
* Releases the HDA lock and TM lock.
*/
-#define DEVHDA_UNLOCK_BOTH(a_pThis) \
+#define DEVHDA_UNLOCK_BOTH(a_pThis, a_SD) \
do { \
PDMCritSectLeave(&(a_pThis)->CritSect); \
- TMTimerUnlock((a_pThis)->pTimer); \
+ TMTimerUnlock((a_pThis)->pTimer[a_SD]); \
} while (0)
#ifdef IN_RING3
@@ -1303,7 +1296,10 @@ static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
#ifdef IN_RING3
- DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
+ /* Get the stream descriptor. */
+ const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
+
+ DEVHDA_LOCK_BOTH_RETURN(pThis, uSD, VINF_IOM_R3_MMIO_WRITE);
/*
* Some guests write too much (that is, 32-bit with the top 8 bit being junk)
@@ -1317,9 +1313,6 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
bool fReset = RT_BOOL(u32Value & HDA_SDCTL_SRST);
bool fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_SDCTL_SRST);
- /* Get the stream descriptor. */
- uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
-
LogFunc(("[SD%RU8] fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
uSD, fRun, fInRun, fReset, fInReset, u32Value));
@@ -1335,7 +1328,7 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
LogFunc(("[SD%RU8] Warning: Invalid stream tag %RU8 specified!\n", uSD, uTag));
- DEVHDA_UNLOCK_BOTH(pThis);
+ DEVHDA_UNLOCK_BOTH(pThis, uSD);
return hdaRegWriteU24(pThis, iReg, u32Value);
}
@@ -1399,13 +1392,30 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
hdaStreamLock(pStream);
+ int rc2;
+
# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+ if (fRun)
+ rc2 = hdaStreamAsyncIOCreate(pStream);
+
hdaStreamAsyncIOLock(pStream);
- hdaStreamAsyncIOEnable(pStream, fRun /* fEnable */);
# endif
- /* (Re-)initialize the stream with current values. */
- int rc2 = hdaStreamInit(pStream, pStream->u8SD);
- AssertRC(rc2);
+ if (fRun)
+ {
+# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+ hdaStreamAsyncIOEnable(pStream, fRun /* fEnable */);
+# endif
+ /* (Re-)initialize the stream with current values. */
+ rc2 = hdaStreamInit(pStream, pStream->u8SD);
+ AssertRC(rc2);
+
+ /* Remove the old stream from the device setup. */
+ hdaRemoveStream(pThis, &pStream->State.Cfg);
+
+ /* Add the stream to the device setup. */
+ rc2 = hdaAddStream(pThis, &pStream->State.Cfg);
+ AssertRC(rc2);
+ }
/* Enable/disable the stream. */
rc2 = hdaStreamEnable(pStream, fRun /* fEnable */);
@@ -1424,7 +1434,7 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);
AssertRC(rc2);
- rc2 = hdaTimerSet(pThis, TMTimerGet(pThis->pTimer) + pStream->State.cTransferTicks, false /* fForce */);
+ rc2 = hdaTimerSet(pThis, pStream, TMTimerGet(pThis->pTimer[pStream->u8SD]) + pStream->State.cTransferTicks, false /* fForce */);
AssertRC(rc2);
}
else
@@ -1452,8 +1462,7 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
int rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
AssertRC(rc2);
- DEVHDA_UNLOCK_BOTH(pThis);
-
+ DEVHDA_UNLOCK_BOTH(pThis, uSD);
return VINF_SUCCESS; /* Always return success to the MMIO handler. */
#else /* !IN_RING3 */
RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
@@ -1464,15 +1473,17 @@ static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
#ifdef IN_RING3
- DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
+ const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, STS, iReg);
- PHDASTREAM pStream = hdaGetStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, STS, iReg));
+ DEVHDA_LOCK_BOTH_RETURN(pThis, uSD, VINF_IOM_R3_MMIO_WRITE);
+
+ PHDASTREAM pStream = hdaGetStreamFromSD(pThis, uSD);
if (!pStream)
{
AssertMsgFailed(("[SD%RU8] Warning: Writing SDSTS on non-attached stream (0x%x)\n",
HDA_SD_NUM_FROM_REG(pThis, STS, iReg), u32Value));
- DEVHDA_UNLOCK_BOTH(pThis);
+ DEVHDA_UNLOCK_BOTH(pThis, uSD);
return hdaRegWriteU16(pThis, iReg, u32Value);
}
@@ -1520,7 +1531,7 @@ static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
hdaProcessInterrupt(pThis, __FUNCTION__);
#endif
- const uint64_t tsNow = TMTimerGet(pThis->pTimer);
+ const uint64_t tsNow = TMTimerGet(pThis->pTimer[uSD]);
Assert(tsNow >= pStream->State.tsTransferLast);
const uint64_t cTicksElapsed = tsNow - pStream->State.tsTransferLast;
@@ -1548,7 +1559,7 @@ static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
pStream->u8SD,
- (TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz) / 1000, (tsNow - pStream->State.tsTransferLast) / 1000));
+ (TMTimerGetFreq(pThis->pTimer[pStream->u8SD]) / pThis->u16TimerHz) / 1000,(tsNow - pStream->State.tsTransferLast) / 1000));
cTicksToNext = 0;
}
@@ -1567,13 +1578,14 @@ static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
pStream->State.cTransferPendingInterrupts--;
/* Re-arm the timer. */
- hdaTimerSet(pThis, tsNow + cTicksToNext, false /* fForce */);
+ LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
+ hdaTimerSet(pThis, pStream, tsNow + cTicksToNext, false /* fForce */);
}
}
hdaStreamUnlock(pStream);
- DEVHDA_UNLOCK_BOTH(pThis);
+ DEVHDA_UNLOCK_BOTH(pThis, uSD);
return VINF_SUCCESS;
#else /* IN_RING3 */
RT_NOREF(pThis, iReg, u32Value);
@@ -1856,9 +1868,7 @@ static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
pCfg->Props.cChannels = 2;
pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
+ rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
}
#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
@@ -1873,9 +1883,7 @@ static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
pCfg->Props.cChannels = (fUseCenter && fUseLFE) ? 2 : 1;
pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
+ rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
}
if ( RT_SUCCESS(rc)
@@ -1889,9 +1897,7 @@ static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
pCfg->Props.cChannels = 2;
pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
+ rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
}
#endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
@@ -1923,17 +1929,13 @@ static int hdaAddStreamIn(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
{
case PDMAUDIORECSOURCE_LINE:
{
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
+ rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
break;
}
#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
case PDMAUDIORECSOURCE_MIC:
{
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
+ rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
break;
}
#endif
@@ -1958,38 +1960,93 @@ static int hdaAddStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- int rc = VINF_SUCCESS;
+ int rc;
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ LogFlowFuncEnter();
+
+ switch (pCfg->enmDir)
{
- int rc2;
+ case PDMAUDIODIR_OUT:
+ rc = hdaAddStreamOut(pThis, pCfg);
+ break;
- switch (pCfg->enmDir)
+ case PDMAUDIODIR_IN:
+ rc = hdaAddStreamIn(pThis, pCfg);
+ break;
+
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ AssertFailed();
+ break;
+ }
+
+ LogFlowFunc(("Returning %Rrc\n", rc));
+
+ return rc;
+}
+
+/**
+ * Removes an audio stream from the device setup using the given configuration.
+ *
+ * @returns IPRT status code.
+ * @param pThis Device state.
+ * @param pCfg Stream configuration to use for removing a stream.
+ */
+static int hdaRemoveStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+ int rc = VINF_SUCCESS;
+
+ PDMAUDIOMIXERCTL enmMixerCtl = PDMAUDIOMIXERCTL_UNKNOWN;
+ switch (pCfg->enmDir)
+ {
+ case PDMAUDIODIR_IN:
{
- case PDMAUDIODIR_OUT:
- rc2 = hdaAddStreamOut(pThis, pCfg);
- break;
+ LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source));
- case PDMAUDIODIR_IN:
- rc2 = hdaAddStreamIn(pThis, pCfg);
- break;
+ switch (pCfg->DestSource.Source)
+ {
+ case PDMAUDIORECSOURCE_LINE: enmMixerCtl = PDMAUDIOMIXERCTL_LINE_IN; break;
+#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
+ case PDMAUDIORECSOURCE_MIC: enmMixerCtl = PDMAUDIOMIXERCTL_MIC_IN; break;
+#endif
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
- default:
- rc2 = VERR_NOT_SUPPORTED;
- AssertFailed();
- break;
+ break;
}
- if ( RT_FAILURE(rc2)
- && (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)) /* We only care about primary drivers here, the rest may fail. */
+ case PDMAUDIODIR_OUT:
{
- if (RT_SUCCESS(rc))
- rc = rc2;
- /* Keep going. */
+ LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Dest));
+
+ switch (pCfg->DestSource.Dest)
+ {
+ case PDMAUDIOPLAYBACKDEST_FRONT: enmMixerCtl = PDMAUDIOMIXERCTL_FRONT; break;
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+ case PDMAUDIOPLAYBACKDEST_CENTER_LFE: enmMixerCtl = PDMAUDIOMIXERCTL_CENTER_LFE; break;
+ case PDMAUDIOPLAYBACKDEST_REAR: enmMixerCtl = PDMAUDIOMIXERCTL_REAR; break;
+#endif
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+ break;
}
+
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
}
+ if (RT_SUCCESS(rc))
+ rc = hdaCodecRemoveStream(pThis->pCodec, enmMixerCtl);
+
+ LogFlowFuncLeaveRC(rc);
return rc;
}
#endif /* IN_RING3 */
@@ -2017,17 +2074,6 @@ static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
int rc = hdaRegWriteU16(pThis, iReg, u32Value);
AssertRC(rc);
- rc = hdaStreamInit(pStream, pStream->u8SD);
- if (RT_SUCCESS(rc))
- {
- /* Add the stream to the device setup. */
- rc = hdaAddStream(pThis, &pStream->State.Cfg);
-# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
- if (RT_SUCCESS(rc))
- rc = hdaStreamAsyncIOCreate(pStream);
-# endif
- }
-
DEVHDA_UNLOCK(pThis);
return VINF_SUCCESS; /* Never return failure. */
#else /* !IN_RING3 */
@@ -2726,61 +2772,41 @@ static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
}
/**
- * Main routine for the device timer.
+ * Main routine for the stream's timer.
*
- * @param pThis HDA state.
+ * @param pDevIns Device instance.
+ * @param pTimer Timer this callback was called for.
+ * @param pvUser Pointer to associated HDASTREAM.
*/
-static void hdaTimerMain(PHDASTATE pThis)
+DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
- AssertPtrReturnVoid(pThis);
+ RT_NOREF(pDevIns, pTimer);
+
+ PHDASTREAM pStream = (PHDASTREAM)pvUser;
+ AssertPtr(pStream);
- STAM_PROFILE_START(&pThis->StatTimer, a);
+ PHDASTATE pThis = pStream->pHDAState;
- DEVHDA_LOCK_BOTH_RETURN_VOID(pThis);
+ DEVHDA_LOCK_BOTH_RETURN_VOID(pStream->pHDAState, pStream->u8SD);
- /* Do all transfers from/to DMA. */
- hdaDoTransfers(pThis);
+ hdaStreamUpdate(pStream, true /* fInTimer */);
/* Flag indicating whether to kick the timer again for a
* new data processing round. */
- bool fSinksActive = false;
+ const bool fSinkActive = AudioMixerSinkIsActive(pStream->pMixSink->pMixSink);
+ const bool fTimerScheduled = hdaStreamTransferIsScheduled(pStream);
- /* Do we need to kick the timer again? */
- if ( AudioMixerSinkIsActive(pThis->SinkFront.pMixSink)
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
- || AudioMixerSinkIsActive(pThis->SinkCenterLFE.pMixSink)
- || AudioMixerSinkIsActive(pThis->SinkRear.pMixSink)
-#endif
- || AudioMixerSinkIsActive(pThis->SinkLineIn.pMixSink)
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
- || AudioMixerSinkIsActive(pThis->SinkMicIn.pMixSink)
-#endif
- )
- {
- fSinksActive = true;
- }
-
- bool fTimerScheduled = false;
- if ( hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkFront))
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
- || hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkMicIn))
-#endif
- || hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkLineIn)))
- {
- fTimerScheduled = true;
- }
-
- Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinksActive, fTimerScheduled));
+ Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinkActive, fTimerScheduled));
- if ( fSinksActive
+ if ( fSinkActive
&& !fTimerScheduled)
{
- hdaTimerSet(pThis, TMTimerGet(pThis->pTimer) + TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz, true /* fForce */);
+ hdaTimerSet(pThis, pStream,
+ TMTimerGet(pThis->pTimer[pStream->u8SD]) + TMTimerGetFreq(pThis->pTimer[pStream->u8SD]) / pStream->pHDAState->u16TimerHz,
+ true /* fForce */);
}
- DEVHDA_UNLOCK_BOTH(pThis);
-
- STAM_PROFILE_STOP(&pThis->StatTimer, a);
+ DEVHDA_UNLOCK_BOTH(pThis, pStream->u8SD);
}
#ifdef HDA_USE_DMA_ACCESS_HANDLER
@@ -3010,9 +3036,13 @@ static void hdaGCTLReset(PHDASTATE pThis)
for (uint8_t uSD = 0; uSD < HDA_MAX_STREAMS; ++uSD)
{
- /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
- HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_SDCTL_RUN;
- hdaStreamReset(pThis, &pThis->aStreams[uSD], uSD);
+ int rc2 = hdaStreamEnable(&pThis->aStreams[uSD], false /* fEnable */);
+ if (RT_SUCCESS(rc2))
+ {
+ /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
+ HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_SDCTL_RUN;
+ hdaStreamReset(pThis, &pThis->aStreams[uSD], uSD);
+ }
}
/* Clear stream tags <-> objects mapping table. */
@@ -3025,45 +3055,6 @@ static void hdaGCTLReset(PHDASTATE pThis)
LogRel(("HDA: Reset\n"));
}
-/**
- * Timer callback which handles the audio data transfers on a periodic basis.
- *
- * @param pDevIns Device instance.
- * @param pTimer Timer which was used when calling this.
- * @param pvUser User argument as PHDASTATE.
- */
-static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
-{
- RT_NOREF(pDevIns, pTimer);
-
- PHDASTATE pThis = (PHDASTATE)pvUser;
- Assert(pThis == PDMINS_2_DATA(pDevIns, PHDASTATE));
- AssertPtr(pThis);
-
- hdaTimerMain(pThis);
-}
-
-/**
- * Main routine to perform the actual audio data transfers from the HDA streams
- * to the backend(s) and vice versa.
- *
- * @param pThis HDA state.
- */
-static void hdaDoTransfers(PHDASTATE pThis)
-{
- PHDASTREAM pStreamLineIn = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn);
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
- PHDASTREAM pStreamMicIn = hdaGetStreamFromSink(pThis, &pThis->SinkMicIn);
-#endif
- PHDASTREAM pStreamFront = hdaGetStreamFromSink(pThis, &pThis->SinkFront);
-
- hdaStreamUpdate(pStreamFront, true /* fInTimer */);
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
- hdaStreamUpdate(pStreamMicIn, true /* fInTimer */);
-#endif
- hdaStreamUpdate(pStreamLineIn, true /* fInTimer */);
-}
-
#ifdef DEBUG_andy
# define HDA_DEBUG_DMA
#endif
@@ -3582,8 +3573,6 @@ static int hdaLoadExecPost(PHDASTATE pThis)
{
int rc = VINF_SUCCESS;
- uint64_t tsExpire = 0; /* Timestamp of new timer expiration time / Whether to resume the device timer. */
-
/*
* Enable all previously active streams.
*/
@@ -3620,13 +3609,8 @@ static int hdaLoadExecPost(PHDASTATE pThis)
/* (Re-)install the DMA handler. */
hdaStreamRegisterDMAHandlers(pThis, pStream);
#endif
- /* Determine the earliest timing slot we need to use. */
- if (tsExpire)
- tsExpire = RT_MIN(tsExpire, hdaStreamTransferGetNext(pStream));
- else
- tsExpire = hdaStreamTransferGetNext(pStream);
-
- Log2Func(("[SD%RU8] tsExpire=%RU64\n", pStream->u8SD, tsExpire));
+ if (hdaStreamTransferIsScheduled(pStream))
+ hdaTimerSet(pThis, pStream, hdaStreamTransferGetNext(pStream), true /* fForce */);
/* Also keep track of the currently active streams. */
pThis->cStreamsActive++;
@@ -3634,13 +3618,6 @@ static int hdaLoadExecPost(PHDASTATE pThis)
}
}
- /* Start the timer if one of the above streams were active during taking the saved state. */
- if (tsExpire)
- {
- LogFunc(("Resuming timer at %RU64\n", tsExpire));
- hdaTimerSet(pThis, tsExpire, true /* fForce */);
- }
-
LogFlowFuncLeaveRC(rc);
return rc;
}
@@ -5076,6 +5053,24 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
*/
for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
{
+ /* Create the emulation timer (per stream).
+ *
+ * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver
+ * relies on exact (virtual) DMA timing and uses DMA Position Buffers
+ * instead of the LPIB registers.
+ */
+ char szTimer[16];
+ RTStrPrintf2(szTimer, sizeof(szTimer), "HDA SD%RU8", i);
+
+ rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaTimer, &pThis->aStreams[i],
+ TMTIMER_FLAGS_NO_CRIT_SECT, szTimer, &pThis->pTimer[i]);
+ AssertRCReturn(rc, rc);
+
+ /* Use our own critcal section for the device timer.
+ * That way we can control more fine-grained when to lock what. */
+ rc = TMR3TimerSetCritSect(pThis->pTimer[i], &pThis->CritSect);
+ AssertRCReturn(rc, rc);
+
rc = hdaStreamCreate(&pThis->aStreams[i], pThis, i /* u8SD */);
AssertRC(rc);
}
@@ -5267,24 +5262,6 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
}
}
- if (RT_SUCCESS(rc))
- {
- /* Create the emulation timer.
- *
- * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver
- * relies on exact (virtual) DMA timing and uses DMA Position Buffers
- * instead of the LPIB registers.
- */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaTimer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "HDA Timer", &pThis->pTimer);
- AssertRCReturn(rc, rc);
-
- /* Use our own critcal section for the device timer.
- * That way we can control more fine-grained when to lock what. */
- rc = TMR3TimerSetCritSect(pThis->pTimer, &pThis->CritSect);
- AssertRCReturn(rc, rc);
- }
-
# ifdef VBOX_WITH_STATISTICS
if (RT_SUCCESS(rc))
{
diff --git a/src/VBox/Devices/Audio/DevHDA.h b/src/VBox/Devices/Audio/DevHDA.h
index 5fdb659..d6f74df 100644
--- a/src/VBox/Devices/Audio/DevHDA.h
+++ b/src/VBox/Devices/Audio/DevHDA.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2016-2017 Oracle Corporation
+ * Copyright (C) 2016-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -156,8 +156,8 @@ typedef struct HDASTATE
bool fRCEnabled;
/** Number of active (running) SDn streams. */
uint8_t cStreamsActive;
- /** The timer for pumping data thru the attached LUN drivers. */
- PTMTIMERR3 pTimer;
+ /** The stream timers for pumping data thru the attached LUN drivers. */
+ PTMTIMERR3 pTimer[HDA_MAX_STREAMS];
#ifdef VBOX_WITH_STATISTICS
STAMPROFILE StatTimer;
STAMPROFILE StatIn;
diff --git a/src/VBox/Devices/Audio/DevHDACommon.cpp b/src/VBox/Devices/Audio/DevHDACommon.cpp
index 49edc44..4b9a956 100644
--- a/src/VBox/Devices/Audio/DevHDACommon.cpp
+++ b/src/VBox/Devices/Audio/DevHDACommon.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2017 Oracle Corporation
+ * Copyright (C) 2017-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -403,8 +403,6 @@ int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t
/* Sanity checks. */
Assert(cbChunk <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
- Assert(cbChunk % pStream->State.cbFrameSize == 0);
- Assert((cbChunk >> 1) >= 1);
if (pStream->Dbg.Runtime.fEnabled)
DrvAudioHlpFileWrite(pStream->Dbg.Runtime.pFileDMA, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk, 0 /* fFlags */);
@@ -676,6 +674,7 @@ bool hdaBDLENeedsInterrupt(PHDABDLE pBDLE)
*
* @returns Whether the new expiration time was set or not.
* @param pThis HDA state.
+ * @param pStream HDA stream to set timer for.
* @param tsExpire New (virtual) expiration time to set.
* @param fForce Whether to force setting the expiration time or not.
*
@@ -688,35 +687,31 @@ bool hdaBDLENeedsInterrupt(PHDABDLE pBDLE)
*
* Forcing a new expiration time will override the above mechanism.
*/
-bool hdaTimerSet(PHDASTATE pThis, uint64_t tsExpire, bool fForce)
+bool hdaTimerSet(PHDASTATE pThis, PHDASTREAM pStream, uint64_t tsExpire, bool fForce)
{
- AssertPtr(pThis->pTimer);
+ AssertPtr(pThis);
+ AssertPtr(pStream);
uint64_t tsExpireMin = tsExpire;
if (!fForce)
{
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
- {
- PHDASTREAM pStream = &pThis->aStreams[i];
-
- if (hdaStreamTransferIsScheduled(pStream))
- tsExpireMin = RT_MIN(tsExpireMin, hdaStreamTransferGetNext(pStream));
- }
+ if (hdaStreamTransferIsScheduled(pStream))
+ tsExpireMin = RT_MIN(tsExpireMin, hdaStreamTransferGetNext(pStream));
}
- const uint64_t tsNow = TMTimerGet(pThis->pTimer);
+ AssertPtr(pThis->pTimer[pStream->u8SD]);
+
+#ifdef VBOX_STRICT
+ const uint64_t tsNow = TMTimerGet(pThis->pTimer[pStream->u8SD]);
if (tsExpireMin < tsNow) /* Make sure to not go backwards in time. */
tsExpireMin = tsNow;
+#endif
- Log3Func(("u64Epxire=%RU64 -> u64ExpireMin=%RU64, fForce=%RTbool [%s]\n",
- tsExpire, tsExpireMin, fForce, tsExpireMin == tsExpire ? "OK" : "DELAYED"));
-
- int rc2 = TMTimerSet(pThis->pTimer, tsExpireMin);
- AssertRC(rc2);
+ int rc2 = TMTimerSet(pThis->pTimer[pStream->u8SD], tsExpireMin);
+ AssertRC(rc2);
- return tsExpireMin == tsExpire;
+ return true;
}
#endif /* IN_RING3 */
-
diff --git a/src/VBox/Devices/Audio/DevHDACommon.h b/src/VBox/Devices/Audio/DevHDACommon.h
index 633c891..67216ee 100644
--- a/src/VBox/Devices/Audio/DevHDACommon.h
+++ b/src/VBox/Devices/Audio/DevHDACommon.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2016-2017 Oracle Corporation
+ * Copyright (C) 2016-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -635,7 +635,7 @@ bool hdaBDLENeedsInterrupt(PHDABDLE pBDLE);
* @{
*/
#ifdef IN_RING3
-bool hdaTimerSet(PHDASTATE pThis, uint64_t u64Expire, bool fForce);
+bool hdaTimerSet(PHDASTATE pThis, PHDASTREAM pStream, uint64_t u64Expire, bool fForce);
#endif /* IN_RING3 */
/** @} */
diff --git a/src/VBox/Devices/Audio/DevSB16.cpp b/src/VBox/Devices/Audio/DevSB16.cpp
index d6e3dff..e135523 100644
--- a/src/VBox/Devices/Audio/DevSB16.cpp
+++ b/src/VBox/Devices/Audio/DevSB16.cpp
@@ -1304,9 +1304,6 @@ static void sb16ResetLegacy(PSB16STATE pThis)
RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
sb16CloseOut(pThis);
-
- int rc2 = sb16OpenOut(pThis, pCfg);
- AssertRC(rc2);
}
static void sb16Reset(PSB16STATE pThis)
@@ -1978,29 +1975,30 @@ static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void
if (!pStream)
continue;
-#ifdef DEBUG
+#ifdef VBOX_STRICT
+ /*
+ * Sanity. Make sure that all streams have the same configuration
+ * to get SB16's DMA transfers right.
+ *
+ * SB16 only allows one output configuration per serial data out,
+ * so check if all streams have the same configuration.
+ */
PSB16DRIVER pDrvPrev = RTListNodeGetPrev(&pDrv->Node, SB16DRIVER, Node);
if ( pDrvPrev
&& !RTListNodeIsDummy(&pThis->lstDrv, pDrvPrev, SB16DRIVER, Node))
{
PPDMAUDIOSTREAM pStreamPrev = pDrvPrev->Out.pStream;
- AssertPtr(pStreamPrev);
-
- /*
- * Sanity. Make sure that all streams have the same configuration
- * to get SB16's DMA transfers right.
- *
- * SB16 only allows one output configuration per serial data out,
- * so check if all streams have the same configuration.
- */
- AssertMsg(pStream->Cfg.Props.uHz == pStreamPrev->Cfg.Props.uHz,
- ("%RU32Hz vs. %RU32Hz\n", pStream->Cfg.Props.uHz, pStreamPrev->Cfg.Props.uHz));
- AssertMsg(pStream->Cfg.Props.cChannels == pStreamPrev->Cfg.Props.cChannels,
- ("%RU8 vs. %RU8 channels\n", pStream->Cfg.Props.cChannels, pStreamPrev->Cfg.Props.cChannels));
- AssertMsg(pStream->Cfg.Props.cBits == pStreamPrev->Cfg.Props.cBits,
- ("%d vs. %d bits\n", pStream->Cfg.Props.cBits, pStreamPrev->Cfg.Props.cBits));
- AssertMsg(pStream->Cfg.Props.fSigned == pStreamPrev->Cfg.Props.fSigned,
- ("%RTbool vs. %RTbool signed\n", pStream->Cfg.Props.fSigned, pStreamPrev->Cfg.Props.fSigned));
+ if (pStreamPrev)
+ {
+ AssertMsg(pStream->Cfg.Props.uHz == pStreamPrev->Cfg.Props.uHz,
+ ("%RU32Hz vs. %RU32Hz\n", pStream->Cfg.Props.uHz, pStreamPrev->Cfg.Props.uHz));
+ AssertMsg(pStream->Cfg.Props.cChannels == pStreamPrev->Cfg.Props.cChannels,
+ ("%RU8 vs. %RU8 channels\n", pStream->Cfg.Props.cChannels, pStreamPrev->Cfg.Props.cChannels));
+ AssertMsg(pStream->Cfg.Props.cBits == pStreamPrev->Cfg.Props.cBits,
+ ("%d vs. %d bits\n", pStream->Cfg.Props.cBits, pStreamPrev->Cfg.Props.cBits));
+ AssertMsg(pStream->Cfg.Props.fSigned == pStreamPrev->Cfg.Props.fSigned,
+ ("%RTbool vs. %RTbool signed\n", pStream->Cfg.Props.fSigned, pStreamPrev->Cfg.Props.fSigned));
+ }
}
#endif
PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
@@ -2345,9 +2343,13 @@ static void sb16DestroyDrvStream(PSB16STATE pThis, PSB16DRIVER pDrv)
{
pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
- int rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
- if (RT_SUCCESS(rc2))
- pDrv->Out.pStream = NULL;
+ int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, PDMAUDIOSTREAMCMD_DISABLE);
+ AssertRC(rc2);
+
+ rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
+ AssertRC(rc2);
+
+ pDrv->Out.pStream = NULL;
}
}
@@ -2448,16 +2450,7 @@ static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
PSB16DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- if (pDrv->Out.pStream)
- {
- pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
-
- int rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
- if (RT_SUCCESS(rc2))
- pDrv->Out.pStream = NULL;
- }
- }
+ sb16DestroyDrvStream(pThis, pDrv);
}
/**
diff --git a/src/VBox/Devices/Audio/DrvAudio.cpp b/src/VBox/Devices/Audio/DrvAudio.cpp
index 5d959f5..9576171 100644
--- a/src/VBox/Devices/Audio/DrvAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvAudio.cpp
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -143,7 +143,7 @@ static const char *drvAudioGetConfStr(PCFGMNODE pCfgHandle, const char *pszKey,
*
* @returns Stringified stream status flags. Must be free'd with RTStrFree().
* "NONE" if no flags set.
- * @param fFlags Stream status flags to convert.
+ * @param fStatus Stream status flags to convert.
*/
static char *dbgAudioStreamStatusToStr(PDMAUDIOSTREAMSTS fStatus)
{
@@ -188,7 +188,7 @@ static char *dbgAudioStreamStatusToStr(PDMAUDIOSTREAMSTS fStatus)
return pszFlags;
}
-#endif /* LOG_ENABLED */
+#endif /* defined(VBOX_STRICT) || defined(LOG_ENABLED) */
/**
* Returns the host stream part of an audio stream pair, or NULL
@@ -516,7 +516,7 @@ static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM
PDMAUDIOSTREAMCMD_DISABLE);
if (RT_SUCCESS(rc))
{
- pHstStream->fStatus &= ~(PDMAUDIOSTREAMSTS_FLAG_ENABLED | PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE);
+ pHstStream->fStatus = PDMAUDIOSTREAMSTS_FLAG_INITIALIZED; /* Reset to initialized state. */
AudioMixBufReset(&pHstStream->MixBuf);
}
}
@@ -1301,7 +1301,7 @@ static int drvAudioStreamPlayNonInterleaved(PDRVAUDIO pThis,
if (cfToPlay)
{
- uint8_t auBuf[_4K]; /** @todo Get rid of this here. */
+ uint8_t auBuf[256]; /** @todo Get rid of this here. */
uint32_t cbLeft = AUDIOMIXBUF_F2B(&pHstStream->MixBuf, cfToPlay);
uint32_t cbChunk = sizeof(auBuf);
@@ -1309,37 +1309,38 @@ static int drvAudioStreamPlayNonInterleaved(PDRVAUDIO pThis,
while (cbLeft)
{
uint32_t cfRead = 0;
- rc = AudioMixBufReadCirc(&pHstStream->MixBuf, auBuf, RT_MIN(cbChunk, cbLeft), &cfRead);
- if ( !cfRead
- || RT_FAILURE(rc))
- {
+ rc = AudioMixBufAcquireReadBlock(&pHstStream->MixBuf, auBuf, RT_MIN(cbChunk, cbLeft), &cfRead);
+ if (RT_FAILURE(rc))
break;
- }
uint32_t cbRead = AUDIOMIXBUF_F2B(&pHstStream->MixBuf, cfRead);
Assert(cbRead <= cbChunk);
+ uint32_t cfPlayed = 0;
uint32_t cbPlayed = 0;
rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream->pvBackend,
auBuf, cbRead, &cbPlayed);
- if ( RT_FAILURE(rc)
- || !cbPlayed)
+ if ( RT_SUCCESS(rc)
+ && cbPlayed)
{
- break;
+ if (pThis->Dbg.fEnabled)
+ DrvAudioHlpFileWrite(pHstStream->Out.Dbg.pFilePlayNonInterleaved, auBuf, cbPlayed, 0 /* fFlags */);
+
+ if (cbRead != cbPlayed)
+ LogRel2(("Audio: Host stream '%s' played wrong amount (%RU32 bytes read but played %RU32 (%RI32), writable was %RU32)\n",
+ pHstStream->szName, cbRead, cbPlayed, cbRead - cbPlayed, cbWritable));
+
+ cfPlayed = AUDIOMIXBUF_B2F(&pHstStream->MixBuf, cbPlayed);
+ cfPlayedTotal += cfPlayed;
+
+ Assert(cbLeft >= cbPlayed);
+ cbLeft -= cbPlayed;
}
- if (pThis->Dbg.fEnabled)
- DrvAudioHlpFileWrite(pHstStream->Out.Dbg.pFilePlayNonInterleaved, auBuf, cbPlayed, 0 /* fFlags */);
+ AudioMixBufReleaseReadBlock(&pHstStream->MixBuf, cfPlayed);
- AssertMsg(cbPlayed <= cbRead, ("Played more than available (%RU32 available but got %RU32)\n", cbRead, cbPlayed));
-#if 0 /** @todo Also handle mono channels. Needs fixing */
- AssertMsg(cbPlayed % 2 == 0,
- ("Backend for stream '%s' returned uneven played bytes count (cfRead=%RU32, cbPlayed=%RU32)\n",
- pHstStream->szName, cfRead, cbPlayed));*/
-#endif
- cfPlayedTotal += AUDIOMIXBUF_B2F(&pHstStream->MixBuf, cbPlayed);
- Assert(cbLeft >= cbPlayed);
- cbLeft -= cbPlayed;
+ if (RT_FAILURE(rc))
+ break;
}
}
}
@@ -2175,12 +2176,12 @@ static void drvAudioStateHandler(PPDMDRVINS pDrvIns, PDMAUDIOSTREAMCMD enmCmd)
int rc2 = RTCritSectEnter(&pThis->CritSect);
AssertRC(rc2);
- if (!pThis->pHostDrvAudio)
- return;
-
- PPDMAUDIOSTREAM pHstStream;
- RTListForEach(&pThis->lstHstStreams, pHstStream, PDMAUDIOSTREAM, Node)
- drvAudioStreamControlInternalBackend(pThis, pHstStream, enmCmd);
+ if (pThis->pHostDrvAudio)
+ {
+ PPDMAUDIOSTREAM pHstStream;
+ RTListForEach(&pThis->lstHstStreams, pHstStream, PDMAUDIOSTREAM, Node)
+ drvAudioStreamControlInternalBackend(pThis, pHstStream, enmCmd);
+ }
rc2 = RTCritSectLeave(&pThis->CritSect);
AssertRC(rc2);
@@ -2304,8 +2305,8 @@ static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDM
while (cToRead)
{
uint32_t cRead;
- rc = AudioMixBufReadCirc(&pGstStream->MixBuf, (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pGstStream->MixBuf, cReadTotal),
- AUDIOMIXBUF_F2B(&pGstStream->MixBuf, cToRead), &cRead);
+ rc = AudioMixBufAcquireReadBlock(&pGstStream->MixBuf, (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pGstStream->MixBuf, cReadTotal),
+ AUDIOMIXBUF_F2B(&pGstStream->MixBuf, cToRead), &cRead);
if (RT_FAILURE(rc))
break;
@@ -2321,6 +2322,8 @@ static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDM
cToRead -= cRead;
cReadTotal += cRead;
+
+ AudioMixBufReleaseReadBlock(&pGstStream->MixBuf, cRead);
}
if (cReadTotal)
@@ -3122,7 +3125,7 @@ static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM
char *pszHstSts = dbgAudioStreamStatusToStr(pHstStream->fStatus);
LogFunc(("[%s] fStatus=%s\n", pHstStream->szName, pszHstSts));
RTStrFree(pszHstSts);
-#endif /* LOG_ENABLED */
+#endif
if (pHstStream->fStatus & PDMAUDIOSTREAMSTS_FLAG_INITIALIZED)
{
@@ -3133,8 +3136,12 @@ static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM
if (RT_SUCCESS(rc))
{
pHstStream->fStatus &= ~PDMAUDIOSTREAMSTS_FLAG_INITIALIZED;
-#if 0 /** @todo r=andy Disabled for now -- need to test this on Windows hosts. */
- Assert(pHstStream->fStatus == PDMAUDIOSTRMSTS_FLAG_NONE);
+
+#ifdef LOG_ENABLED
+ /* This is not fatal, but log it anyway. */
+ if (pHstStream->fStatus != PDMAUDIOSTREAMSTS_FLAG_NONE)
+ LogFunc(("[%s] Warning: Stream still has %s set when destroying, must properly drain first\n",
+ pHstStream->szName, pszHstSts));
#endif
}
}
@@ -3232,7 +3239,10 @@ static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
* in drvAudioDestruct(). */
PPDMAUDIOSTREAM pStream;
RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
+ {
+ drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
drvAudioStreamDestroyInternalBackend(pThis, pStream);
+ }
/*
* Last call for the driver below us.
@@ -3369,8 +3379,13 @@ static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
LogFlowFuncEnter();
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
+ int rc2;
+
+ if (RTCritSectIsInitialized(&pThis->CritSect))
+ {
+ rc2 = RTCritSectEnter(&pThis->CritSect);
+ AssertRC(rc2);
+ }
/*
* Note: No calls here to the driver below us anymore,
@@ -3426,11 +3441,14 @@ static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
drvAudioCallbackDestroy(pCB);
#endif
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
+ if (RTCritSectIsInitialized(&pThis->CritSect))
+ {
+ rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
- rc2 = RTCritSectDelete(&pThis->CritSect);
- AssertRC(rc2);
+ rc2 = RTCritSectDelete(&pThis->CritSect);
+ AssertRC(rc2);
+ }
#ifdef VBOX_WITH_STATISTICS
PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pThis->Stats.TotalStreamsActive);
diff --git a/src/VBox/Devices/Audio/DrvAudio.h b/src/VBox/Devices/Audio/DrvAudio.h
index 4ed2c00..745a980 100644
--- a/src/VBox/Devices/Audio/DrvAudio.h
+++ b/src/VBox/Devices/Audio/DrvAudio.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -151,11 +151,13 @@ const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt);
void DrvAudioHlpClearBuf(const PPDMAUDIOPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cFrames);
uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels);
uint32_t DrvAudioHlpCalcBitrate(const PPDMAUDIOPCMPROPS pProps);
+uint32_t DrvAudioHlpMsToBytes(const PPDMAUDIOPCMPROPS pProps, uint32_t uMs);
bool DrvAudioHlpPCMPropsAreEqual(const PPDMAUDIOPCMPROPS pPCMProps1, const PPDMAUDIOPCMPROPS pPCMProps2);
bool DrvAudioHlpPCMPropsAreEqual(const PPDMAUDIOPCMPROPS pPCMProps, const PPDMAUDIOSTREAMCFG pCfg);
bool DrvAudioHlpPCMPropsAreValid(const PPDMAUDIOPCMPROPS pProps);
void DrvAudioHlpPCMPropsPrint(const PPDMAUDIOPCMPROPS pProps);
int DrvAudioHlpPCMPropsToStreamCfg(const PPDMAUDIOPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg);
+const char *DrvAudioHlpPlaybackDstToStr(const PDMAUDIOPLAYBACKDEST enmPlaybackDst);
const char *DrvAudioHlpRecSrcToStr(const PDMAUDIORECSOURCE enmRecSource);
void DrvAudioHlpStreamCfgPrint(const PPDMAUDIOSTREAMCFG pCfg);
bool DrvAudioHlpStreamCfgIsValid(const PPDMAUDIOSTREAMCFG pCfg);
@@ -193,6 +195,7 @@ int DrvAudioHlpFileOpen(PPDMAUDIOFILE pFile, uint32_t fOpen, const PPDMAUDIOPCMP
int DrvAudioHlpFileClose(PPDMAUDIOFILE pFile);
int DrvAudioHlpFileDelete(PPDMAUDIOFILE pFile);
size_t DrvAudioHlpFileGetDataSize(PPDMAUDIOFILE pFile);
+bool DrvAudioHlpFileIsOpen(PPDMAUDIOFILE pFile);
int DrvAudioHlpFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags);
#define AUDIO_MAKE_FOURCC(c0, c1, c2, c3) RT_H2LE_U32_C(RT_MAKE_U32_FROM_U8(c0, c1, c2, c3))
diff --git a/src/VBox/Devices/Audio/DrvAudioCommon.cpp b/src/VBox/Devices/Audio/DrvAudioCommon.cpp
index 9917a01..840d72a 100644
--- a/src/VBox/Devices/Audio/DrvAudioCommon.cpp
+++ b/src/VBox/Devices/Audio/DrvAudioCommon.cpp
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -621,6 +621,28 @@ char *DrvAudioHlpAudDevFlagsToStrA(PDMAUDIODEVFLAG fFlags)
}
/**
+ * Converts a playback destination enumeration to a string.
+ *
+ * @returns Stringified playback destination, or "Unknown", if not found.
+ * @param enmPlaybackDst Playback destination to convert.
+ */
+const char *DrvAudioHlpPlaybackDstToStr(const PDMAUDIOPLAYBACKDEST enmPlaybackDst)
+{
+ switch (enmPlaybackDst)
+ {
+ case PDMAUDIOPLAYBACKDEST_UNKNOWN: return "Unknown";
+ case PDMAUDIOPLAYBACKDEST_FRONT: return "Front";
+ case PDMAUDIOPLAYBACKDEST_CENTER_LFE: return "Center / LFE";
+ case PDMAUDIOPLAYBACKDEST_REAR: return "Rear";
+ default:
+ break;
+ }
+
+ AssertMsgFailed(("Invalid playback destination %ld\n", enmPlaybackDst));
+ return "Unknown";
+}
+
+/**
* Converts a recording source enumeration to a string.
*
* @returns Stringified recording source, or "Unknown", if not found.
@@ -1030,6 +1052,23 @@ uint32_t DrvAudioHlpCalcBitrate(const PPDMAUDIOPCMPROPS pProps)
}
/**
+ * Returns the amount of bytes for a given time (in ms) and PCM properties.
+ *
+ * @return uint32_t Calculated amount of bytes.
+ * @param pProps PCM properties to calculate amount of bytes for.
+ * @param uMs Time (in ms) to calculate amount of bytes for.
+ */
+uint32_t DrvAudioHlpMsToBytes(const PPDMAUDIOPCMPROPS pProps, uint32_t uMs)
+{
+ AssertPtrReturn(pProps, 0);
+
+ if (!uMs)
+ return 0;
+
+ return float(((pProps->cBits / 8) * pProps->cChannels * pProps->uHz) / 1000) * uMs;
+}
+
+/**
* Sanitizes the file name component so that unsupported characters
* will be replaced by an underscore ("_").
*
@@ -1102,51 +1141,49 @@ int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, c
break;
}
+ char szFileName[RTPATH_MAX + 1];
+ szFileName[0] = '\0';
+
if (fFlags & PDMAUDIOFILENAME_FLAG_TS)
{
- char szTime[64];
RTTIMESPEC time;
- if (!RTTimeSpecToString(RTTimeNow(&time), szTime, sizeof(szTime)))
+ if (!RTTimeSpecToString(RTTimeNow(&time), szFileName, sizeof(szFileName)))
{
rc = VERR_BUFFER_OVERFLOW;
break;
}
- rc = DrvAudioHlpSanitizeFileName(szTime, sizeof(szTime));
+ rc = DrvAudioHlpSanitizeFileName(szFileName, sizeof(szFileName));
if (RT_FAILURE(rc))
break;
- rc = RTStrCat(szFilePath, sizeof(szFilePath), szTime);
- if (RT_FAILURE(rc))
- break;
-
- rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
+ rc = RTStrCat(szFileName, sizeof(szFileName), "-");
if (RT_FAILURE(rc))
break;
}
- rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
+ rc = RTStrCat(szFileName, sizeof(szFileName), pszName);
if (RT_FAILURE(rc))
break;
- rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
+ rc = RTStrCat(szFileName, sizeof(szFileName), "-");
if (RT_FAILURE(rc))
break;
char szInst[16];
RTStrPrintf2(szInst, sizeof(szInst), "%RU32", uInstance);
- rc = RTStrCat(szFilePath, sizeof(szFilePath), szInst);
+ rc = RTStrCat(szFileName, sizeof(szFileName), szInst);
if (RT_FAILURE(rc))
break;
switch (enmType)
{
case PDMAUDIOFILETYPE_RAW:
- rc = RTStrCat(szFilePath, sizeof(szFilePath), ".pcm");
+ rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");
break;
case PDMAUDIOFILETYPE_WAV:
- rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
+ rc = RTStrCat(szFileName, sizeof(szFileName), ".wav");
break;
default:
@@ -1157,6 +1194,10 @@ int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, c
if (RT_FAILURE(rc))
break;
+ rc = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
+ if (RT_FAILURE(rc))
+ break;
+
RTStrPrintf2(pszFile, cchFile, "%s", szFilePath);
} while (0);
@@ -1393,8 +1434,11 @@ int DrvAudioHlpFileDelete(PPDMAUDIOFILE pFile)
AssertPtrReturn(pFile, VERR_INVALID_POINTER);
int rc = RTFileDelete(pFile->szName);
-
- if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
+ if (RT_SUCCESS(rc))
+ {
+ LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
+ }
+ else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
rc = VINF_SUCCESS;
if (RT_FAILURE(rc))
@@ -1433,6 +1477,20 @@ size_t DrvAudioHlpFileGetDataSize(PPDMAUDIOFILE pFile)
}
/**
+ * Returns whether the given audio file is open and in use or not.
+ *
+ * @return bool True if open, false if not.
+ * @param pFile Audio file handle to check open status for.
+ */
+bool DrvAudioHlpFileIsOpen(PPDMAUDIOFILE pFile)
+{
+ if (!pFile)
+ return false;
+
+ return RTFileIsValid(pFile->hFile);
+}
+
+/**
* Write PCM data to a wave (.WAV) file.
*
* @returns IPRT status code.
diff --git a/src/VBox/Devices/Audio/DrvHostDSound.cpp b/src/VBox/Devices/Audio/DrvHostDSound.cpp
index 0d67df6..b2b5262 100644
--- a/src/VBox/Devices/Audio/DrvHostDSound.cpp
+++ b/src/VBox/Devices/Audio/DrvHostDSound.cpp
@@ -69,9 +69,12 @@
} else DSLOG(a); \
} while (0)
-
/** Maximum number of attempts to restore the sound buffer before giving up. */
#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3
+/** Default input latency (in ms). */
+#define DRV_DSOUND_DEFAULT_LATENCY_MS_IN 50
+/** Default output latency (in ms). */
+#define DRV_DSOUND_DEFAULT_LATENCY_MS_OUT 50
/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
@@ -89,25 +92,23 @@ typedef FNDIRECTSOUNDCAPTUREENUMERATEW *PFNDIRECTSOUNDCAPTUREENUMERATEW;
typedef HRESULT WINAPI FNDIRECTSOUNDCAPTURECREATE8(LPCGUID lpcGUID, LPDIRECTSOUNDCAPTURE8 *lplpDSC, LPUNKNOWN pUnkOuter);
typedef FNDIRECTSOUNDCAPTURECREATE8 *PFNDIRECTSOUNDCAPTURECREATE8;
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
-# define VBOX_DSOUND_MAX_EVENTS 3
+#define VBOX_DSOUND_MAX_EVENTS 3
typedef enum DSOUNDEVENT
{
DSOUNDEVENT_NOTIFY = 0,
DSOUNDEVENT_INPUT,
DSOUNDEVENT_OUTPUT,
- } DSOUNDEVENT;
-#endif /* VBOX_WITH_AUDIO_DEVICE_CALLBACKS */
+} DSOUNDEVENT;
typedef struct DSOUNDHOSTCFG
{
- DWORD cbBufferIn;
- DWORD cbBufferOut;
- RTUUID uuidPlay;
- LPCGUID pGuidPlay;
- RTUUID uuidCapture;
- LPCGUID pGuidCapture;
+ unsigned int msLatencyIn;
+ unsigned int msLatencyOut;
+ RTUUID uuidPlay;
+ LPCGUID pGuidPlay;
+ RTUUID uuidCapture;
+ LPCGUID pGuidCapture;
} DSOUNDHOSTCFG, *PDSOUNDHOSTCFG;
typedef struct DSOUNDSTREAM
@@ -118,6 +119,13 @@ typedef struct DSOUNDSTREAM
uint8_t uAlign;
/** Whether this stream is in an enable state on the DirectSound side. */
bool fEnabled;
+ /** The stream's critical section for synchronizing access. */
+ RTCRITSECT CritSect;
+ /** The internal playback / capturing buffer. */
+ PRTCIRCBUF pCircBuf;
+ /** Size (in bytes) of the DirectSound buffer.
+ * Note: This in *not* the size of the circular buffer above! */
+ DWORD cbBufSize;
union
{
struct
@@ -127,9 +135,8 @@ typedef struct DSOUNDSTREAM
LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
/** Current read offset (in bytes) within the DSB. */
DWORD offReadPos;
- /** Size (in bytes) of the DirectSound buffer. */
- DWORD cbBufSize;
- HRESULT hrLastCapture;
+ /** Number of buffer overruns happened. Used for logging. */
+ uint8_t cOverruns;
} In;
struct
{
@@ -144,10 +151,14 @@ typedef struct DSOUNDSTREAM
DWORD offPlayCursorLastPlayed;
/** Total amount (in bytes) written. */
uint64_t cbWritten;
- /** Size (in bytes) of the DirectSound buffer. */
- DWORD cbBufSize;
+ /** Total amount (in bytes) played (to the DirectSound buffer). */
+ uint64_t cbPlayed;
/** Flag indicating whether playback was (re)started. */
- bool fRestartPlayback;
+ bool fFirstPlayback;
+ /** Timestamp (in ms) of When the last playback has happened. */
+ uint64_t tsLastPlayMs;
+ /** Number of buffer underruns happened. Used for logging. */
+ uint8_t cUnderruns;
} Out;
};
} DSOUNDSTREAM, *PDSOUNDSTREAM;
@@ -165,7 +176,7 @@ typedef struct DRVHOSTDSOUND
/** List of found host output devices. */
RTLISTANCHOR lstDevOutput;
/** DirectSound configuration options. */
- DSOUNDHOSTCFG cfg;
+ DSOUNDHOSTCFG Cfg;
/** Whether this backend supports any audio input. */
bool fEnabledIn;
/** Whether this backend supports any audio output. */
@@ -182,9 +193,6 @@ typedef struct DRVHOSTDSOUND
* Can be NULL if not being used / registered. */
PFNPDMHOSTAUDIOCALLBACK pfnCallback;
#endif
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- /** Pointer to the audio connector interface of the driver/device above us. */
- PPDMIAUDIOCONNECTOR pUpIAudioConnector;
/** Stopped indicator. */
bool fStopped;
/** Shutdown indicator. */
@@ -193,14 +201,10 @@ typedef struct DRVHOSTDSOUND
RTTHREAD Thread;
/** Array of events to wait for in notification thread. */
HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
- /** Number of events to wait for in notification thread.
- * Must not exceed VBOX_DSOUND_MAX_EVENTS. */
- uint8_t cEvents;
/** Pointer to the input stream. */
PDSOUNDSTREAM pDSStrmIn;
/** Pointer to the output stream. */
PDSOUNDSTREAM pDSStrmOut;
-#endif
} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
/** No flags specified. */
@@ -235,13 +239,14 @@ typedef struct DSOUNDDEV
* Internal Functions *
*********************************************************************************************************************************/
static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
-static HRESULT directSoundCaptureStop(PDSOUNDSTREAM pStreamDS);
+static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush);
+static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush);
static void dsoundDeviceRemove(PDSOUNDDEV pDev);
static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
+
static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
-#endif
+
static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis);
static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum);
@@ -254,7 +259,6 @@ static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
return offEnd >= offBegin ? offEnd - offBegin : cSize - offBegin + offEnd;
}
-
static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
{
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
@@ -264,38 +268,15 @@ static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
pFmt->wFormatTag = WAVE_FORMAT_PCM;
pFmt->nChannels = pCfg->Props.cChannels;
+ pFmt->wBitsPerSample = pCfg->Props.cBits;
pFmt->nSamplesPerSec = pCfg->Props.uHz;
- pFmt->nAvgBytesPerSec = pCfg->Props.uHz << (pCfg->Props.cChannels == 2 ? 1: 0);
- pFmt->nBlockAlign = 1 << (pCfg->Props.cChannels == 2 ? 1 : 0);
+ pFmt->nBlockAlign = pFmt->nChannels * pFmt->wBitsPerSample / 8;
+ pFmt->nAvgBytesPerSec = pFmt->nSamplesPerSec * pFmt->nBlockAlign;
pFmt->cbSize = 0; /* No extra data specified. */
- switch (pCfg->Props.cBits)
- {
- case 8:
- pFmt->wBitsPerSample = 8;
- break;
-
- case 16:
- pFmt->wBitsPerSample = 16;
- pFmt->nAvgBytesPerSec <<= 1;
- pFmt->nBlockAlign <<= 1;
- break;
-
- case 32:
- pFmt->wBitsPerSample = 32;
- pFmt->nAvgBytesPerSec <<= 2;
- pFmt->nBlockAlign <<= 2;
- break;
-
- default:
- AssertMsgFailed(("Wave format for %RU8 bits not supported\n", pCfg->Props.cBits));
- return VERR_NOT_SUPPORTED;
- }
-
return VINF_SUCCESS;
}
-
/**
* Retrieves the number of free bytes available for writing to a DirectSound output stream.
*
@@ -324,12 +305,36 @@ static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD
/* Get the current play position which is used for calculating the free space in the buffer. */
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
- DWORD cbPlayCursor;
- hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayCursor, NULL /* cbWriteCursor */);
+ DWORD cbPlayCursor, cbWriteCursor;
+ hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayCursor, &cbWriteCursor);
if (SUCCEEDED(hr))
{
- *pdwFree = pStreamDS->Out.cbBufSize
- - dsoundRingDistance(pStreamDS->Out.offWritePos, cbPlayCursor, pStreamDS->Out.cbBufSize);
+ int32_t cbDiff = cbWriteCursor - cbPlayCursor;
+ if (cbDiff < 0)
+ cbDiff += pStreamDS->cbBufSize;
+
+ int32_t cbFree = cbPlayCursor - pStreamDS->Out.offWritePos;
+ if (cbFree < 0)
+ cbFree += pStreamDS->cbBufSize;
+
+ if (cbFree > (int32_t)pStreamDS->cbBufSize - cbDiff)
+ {
+ pStreamDS->Out.offWritePos = cbWriteCursor;
+ cbFree = pStreamDS->cbBufSize - cbDiff;
+ }
+
+ /* When starting to use a DirectSound buffer, cbPlayCursor and cbWriteCursor
+ * both point at position 0, so we won't be able to detect how many bytes
+ * are writable that way.
+ *
+ * So use our per-stream written indicator to see if we just started a stream. */
+ if (pStreamDS->Out.cbWritten == 0)
+ cbFree = pStreamDS->cbBufSize;
+
+ DSLOGREL(("DSound: cbPlayCursor=%RU32, cbWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",
+ cbPlayCursor, cbWriteCursor, pStreamDS->Out.offWritePos, cbFree));
+
+ *pdwFree = cbFree;
return VINF_SUCCESS;
}
@@ -350,7 +355,6 @@ static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD
return VERR_NOT_AVAILABLE;
}
-
static char *dsoundGUIDToUtf8StrA(LPCGUID pGUID)
{
if (pGUID)
@@ -370,7 +374,6 @@ static char *dsoundGUIDToUtf8StrA(LPCGUID pGUID)
return RTStrDup("{Default device}");
}
-
/**
* Clears the list of the host's playback + capturing devices.
*
@@ -392,17 +395,18 @@ static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
Assert(RTListIsEmpty(&pThis->lstDevOutput));
}
-
static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
{
RT_NOREF(pThis);
HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
if (FAILED(hr))
+ DSLOG(("DSound: Restoring playback buffer\n"));
+ else
DSLOGREL(("DSound: Restoring playback buffer failed with %Rhrc\n", hr));
+
return hr;
}
-
static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
PVOID pv1, PVOID pv2,
DWORD cb1, DWORD cb2)
@@ -414,7 +418,6 @@ static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8
return hr;
}
-
static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
PVOID pv1, PVOID pv2,
DWORD cb1, DWORD cb2)
@@ -425,28 +428,39 @@ static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
return hr;
}
-
static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
DWORD dwOffset, DWORD dwBytes,
PVOID *ppv1, PVOID *ppv2,
DWORD *pcb1, DWORD *pcb2,
DWORD dwFlags)
{
+ AssertReturn(dwBytes, VERR_INVALID_PARAMETER);
+
HRESULT hr = E_FAIL;
AssertCompile(DRV_DSOUND_RESTORE_ATTEMPTS_MAX > 0);
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
- *ppv1 = *ppv2 = NULL;
- *pcb1 = *pcb2 = 0;
- hr = IDirectSoundBuffer8_Lock(pStreamDS->Out.pDSB, dwOffset, dwBytes, ppv1, pcb1, ppv2, pcb2, dwFlags);
+ PVOID pv1, pv2;
+ DWORD cb1, cb2;
+ hr = IDirectSoundBuffer8_Lock(pStreamDS->Out.pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
if (SUCCEEDED(hr))
{
- if ( (!*ppv1 || !(*pcb1 & pStreamDS->uAlign))
- && (!*ppv2 || !(*pcb2 & pStreamDS->uAlign)) )
+ if ( (!pv1 || !(cb1 & pStreamDS->uAlign))
+ && (!pv2 || !(cb2 & pStreamDS->uAlign)))
+ {
+ if (ppv1)
+ *ppv1 = pv1;
+ if (ppv2)
+ *ppv2 = pv2;
+ if (pcb1)
+ *pcb1 = cb1;
+ if (pcb2)
+ *pcb2 = cb2;
return S_OK;
+ }
DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%#RX32, cb2=%#RX32 (alignment: %#RX32)\n",
*pcb1, *pcb2, pStreamDS->uAlign));
- directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, *ppv1, *ppv2, *pcb1, *pcb2);
+ directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2);
return E_FAIL;
}
@@ -457,11 +471,10 @@ static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
}
- DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc\n", hr));
+ DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc (dwOff=%ld, dwBytes=%ld)\n", hr, dwOffset, dwBytes));
return hr;
}
-
static HRESULT directSoundCaptureLock(PDSOUNDSTREAM pStreamDS,
DWORD dwOffset, DWORD dwBytes,
PVOID *ppv1, PVOID *ppv2,
@@ -498,7 +511,6 @@ static HRESULT directSoundCaptureLock(PDSOUNDSTREAM pStreamDS,
return S_OK;
}
-
/*
* DirectSound playback
*/
@@ -514,7 +526,6 @@ static void directSoundPlayInterfaceDestroy(PDRVHOSTDSOUND pThis)
}
}
-
static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis)
{
if (pThis->pDS != NULL)
@@ -530,7 +541,7 @@ static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis)
}
else
{
- hr = IDirectSound8_Initialize(pThis->pDS, pThis->cfg.pGuidPlay);
+ hr = IDirectSound8_Initialize(pThis->pDS, pThis->Cfg.pGuidPlay);
if (SUCCEEDED(hr))
{
HWND hWnd = GetDesktopWindow();
@@ -554,39 +565,44 @@ static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis)
return hr;
}
-
static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
{
AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pStreamDS, E_POINTER);
- HRESULT hr = S_OK;
+ LogFlowFuncEnter();
- if (pStreamDS->Out.pDSB)
- {
- DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pStreamDS, pStreamDS->Out.pDSB));
+ HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
+ if (FAILED(hr))
+ return hr;
- hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
- if (SUCCEEDED(hr))
- {
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- if (pThis->aEvents[DSOUNDEVENT_OUTPUT] != NULL)
- {
- CloseHandle(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
- pThis->aEvents[DSOUNDEVENT_OUTPUT] = NULL;
+ DSLOG(("DSound: Closing playback stream\n"));
- if (pThis->cEvents)
- pThis->cEvents--;
+ if (pStreamDS->pCircBuf)
+ Assert(RTCircBufUsed(pStreamDS->pCircBuf) == 0);
- pThis->pDSStrmOut = NULL;
- }
+ if (SUCCEEDED(hr))
+ {
+ RTCritSectEnter(&pThis->CritSect);
- int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */);
- AssertRC(rc2);
-#endif
+ if (pStreamDS->pCircBuf)
+ {
+ RTCircBufDestroy(pStreamDS->pCircBuf);
+ pStreamDS->pCircBuf = NULL;
+ }
+
+ if (pStreamDS->Out.pDSB)
+ {
IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB);
pStreamDS->Out.pDSB = NULL;
}
+
+ pThis->pDSStrmOut = NULL;
+
+ RTCritSectLeave(&pThis->CritSect);
+
+ int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */);
+ AssertRC(rc2);
}
if (FAILED(hr))
@@ -595,7 +611,6 @@ static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamD
return hr;
}
-
static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
{
@@ -604,26 +619,37 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
AssertPtrReturn(pCfgReq, E_POINTER);
AssertPtrReturn(pCfgAcq, E_POINTER);
- DSLOG(("DSound: Opening playback stream %p: cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pStreamDS,
- pThis->cfg.cbBufferOut,
+ LogFlowFuncEnter();
+
+ Assert(pStreamDS->Out.pDSB == NULL);
+
+ DSLOG(("DSound: Opening playback stream (uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool)\n",
pCfgReq->Props.uHz,
pCfgReq->Props.cChannels,
pCfgReq->Props.cBits,
pCfgReq->Props.fSigned));
- if (pStreamDS->Out.pDSB != NULL)
- {
- /* Should not happen but be forgiving. */
- DSLOGREL(("DSound: Playback buffer already exists\n"));
- directSoundPlayClose(pThis, pStreamDS);
- }
-
WAVEFORMATEX wfx;
int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
if (RT_FAILURE(rc))
return E_INVALIDARG;
+ DSLOG(("DSound: Requested playback format:\n"
+ " wFormatTag = %RI16\n"
+ " nChannels = %RI16\n"
+ " nSamplesPerSec = %RU32\n"
+ " nAvgBytesPerSec = %RU32\n"
+ " nBlockAlign = %RI16\n"
+ " wBitsPerSample = %RI16\n"
+ " cbSize = %RI16\n",
+ wfx.wFormatTag,
+ wfx.nChannels,
+ wfx.nSamplesPerSec,
+ wfx.nAvgBytesPerSec,
+ wfx.nBlockAlign,
+ wfx.wBitsPerSample,
+ wfx.cbSize));
+
dsoundUpdateStatusInternal(pThis);
HRESULT hr = directSoundPlayInterfaceCreate(pThis);
@@ -653,10 +679,11 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
* of copying own buffer data to our secondary's Direct Sound buffer.
*/
bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
bd.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
-#endif
- bd.dwBufferBytes = pThis->cfg.cbBufferOut;
+
+ bd.dwBufferBytes = DrvAudioHlpMsToBytes(&pCfgReq->Props, pThis->Cfg.msLatencyOut);
+
+ DSLOG(("DSound: Playback buffer is %ld bytes\n", bd.dwBufferBytes));
hr = IDirectSound8_CreateSoundBuffer(pThis->pDS, &bd, &pDSB, NULL);
if (FAILED(hr))
@@ -675,8 +702,10 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
}
/*
- * Query the actual parameters.
+ * Query the actual parameters set for this stream.
+ * Those might be different than the initially requested parameters.
*/
+ RT_ZERO(wfx);
hr = IDirectSoundBuffer8_GetFormat(pStreamDS->Out.pDSB, &wfx, sizeof(wfx), NULL);
if (FAILED(hr))
{
@@ -695,7 +724,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
break;
}
- DSLOG(("DSound: Playback format:\n"
+ DSLOG(("DSound: Acquired playback format:\n"
" dwBufferBytes = %RI32\n"
" dwFlags = 0x%x\n"
" wFormatTag = %RI16\n"
@@ -719,69 +748,51 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
bc.dwBufferBytes, pStreamDS->uAlign + 1));
- if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)
- DSLOGREL(("DSound: Playback buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
- bc.dwBufferBytes, pThis->cfg.cbBufferOut));
-
/*
* Initial state.
* dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
* playback buffer position.
*/
- pStreamDS->Out.cbBufSize = bc.dwBufferBytes;
- DSLOG(("DSound: cMaxSamplesInBuffer=%RU32\n", pStreamDS->Out.cbBufSize));
+ pStreamDS->cbBufSize = bc.dwBufferBytes;
+
+ RTCritSectEnter(&pThis->CritSect);
+
+ rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Double buffering */);
+ AssertRC(rc);
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
/*
* Install notification.
*/
- pThis->aEvents[DSOUNDEVENT_OUTPUT] = CreateEvent(NULL /* Security attribute */,
- FALSE /* bManualReset */, FALSE /* bInitialState */,
- NULL /* lpName */);
- if (pThis->aEvents[DSOUNDEVENT_OUTPUT] == NULL)
- {
- hr = HRESULT_FROM_WIN32(GetLastError());
- DSLOGREL(("DSound: CreateEvent for output failed with %Rhrc\n", hr));
- break;
- }
-
LPDIRECTSOUNDNOTIFY8 pNotify;
hr = IDirectSoundNotify_QueryInterface(pStreamDS->Out.pDSB, IID_IDirectSoundNotify8, (PVOID *)&pNotify);
if (SUCCEEDED(hr))
{
- DSBPOSITIONNOTIFY dsBufPosNotify;
- RT_ZERO(dsBufPosNotify);
- dsBufPosNotify.dwOffset = DSBPN_OFFSETSTOP;
- dsBufPosNotify.hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
+ DSBPOSITIONNOTIFY dsPosNotify[3];
+ RT_ZERO(dsPosNotify);
+
+ dsPosNotify[0].dwOffset = 0;
+ dsPosNotify[0].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
+
+ dsPosNotify[1].dwOffset = float(pStreamDS->cbBufSize * 0.3);
+ dsPosNotify[1].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
+
+ dsPosNotify[2].dwOffset = float(pStreamDS->cbBufSize * 0.6);
+ dsPosNotify[2].hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
- hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 1 /* Count */, &dsBufPosNotify);
+ hr = IDirectSoundNotify_SetNotificationPositions(pNotify, RT_ELEMENTS(dsPosNotify), dsPosNotify);
if (FAILED(hr))
DSLOGREL(("DSound: Setting playback position notification failed with %Rhrc\n", hr));
IDirectSoundNotify_Release(pNotify);
+
+ pThis->pDSStrmOut = pStreamDS;
}
else
DSLOGREL(("DSound: Querying interface for position notification failed with %Rhrc\n", hr));
- if (FAILED(hr))
- break;
-
- pThis->pDSStrmOut = pStreamDS;
-
- Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS);
- pThis->cEvents++;
-
- /* Let the thread know. */
- dsoundNotifyThread(pThis, false /* fShutdown */);
-
- /* Trigger the just installed output notification. */
- hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, 0);
- if (FAILED(hr))
- break;
+ RTCritSectLeave(&pThis->CritSect);
-#endif /* VBOX_WITH_AUDIO_DEVICE_CALLBACKS */
-
- pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pThis->cfg.cbBufferOut);
+ pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
} while (0);
@@ -791,35 +802,36 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
return hr;
}
-
-static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
+static void dsoundPlayClearBuffer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
{
AssertPtrReturnVoid(pStreamDS);
AssertPtr(pStreamDS->pCfg);
PPDMAUDIOPCMPROPS pProps = &pStreamDS->pCfg->Props;
- PVOID pv1, pv2;
- DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pStreamDS,
- 0 /* dwOffset */, pStreamDS->Out.cbBufSize,
- &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
+ HRESULT hr = IDirectSoundBuffer_SetCurrentPosition(pStreamDS->Out.pDSB, 0 /* Position */);
+ if (FAILED(hr))
+ DSLOGREL(("DSound: Setting current position to 0 when clearing buffer failed with %Rhrc\n", hr));
+
+ PVOID pv1;
+ hr = directSoundPlayLock(pThis, pStreamDS,
+ 0 /* dwOffset */, pStreamDS->cbBufSize,
+ &pv1, NULL, 0, 0, DSBLOCK_ENTIREBUFFER);
if (SUCCEEDED(hr))
{
- DWORD len1 = PDMAUDIOPCMPROPS_B2F(pProps, cb1);
- DWORD len2 = PDMAUDIOPCMPROPS_B2F(pProps, cb2);
-
- if (pv1 && len1)
- DrvAudioHlpClearBuf(pProps, pv1, cb1, len1);
+ DrvAudioHlpClearBuf(pProps, pv1, pStreamDS->cbBufSize, PDMAUDIOPCMPROPS_B2F(pProps, pStreamDS->cbBufSize));
- if (pv2 && len2)
- DrvAudioHlpClearBuf(pProps, pv2, cb2, len2);
+ directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, NULL, 0, 0);
- directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2);
+ /* Make sure to get the last playback position and current write position from DirectSound again.
+ * Those positions in theory could have changed, re-fetch them to be sure. */
+ hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB,
+ &pStreamDS->Out.offPlayCursorLastPlayed, &pStreamDS->Out.offWritePos);
+ if (FAILED(hr))
+ DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr));
}
}
-
static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
{
AssertPtrReturn(pThis, E_POINTER);
@@ -854,8 +866,7 @@ static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFE
return hr;
}
-
-static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
+static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
{
AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pStreamDS, E_POINTER);
@@ -866,7 +877,7 @@ static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
{
if (pStreamDS->fEnabled)
{
- DSLOG(("DSound: Stopping playback\n"));
+ DSLOG(("DSound: %s playback\n", fFlush ? "Stopping" : "Pausing"));
hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
if (FAILED(hr))
@@ -876,13 +887,21 @@ static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS
hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
}
- if (SUCCEEDED(hr))
- pStreamDS->fEnabled = false;
+ pStreamDS->fEnabled = false;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if ( fFlush
+ && pStreamDS->pCircBuf)
+ {
+ RTCircBufReset(pStreamDS->pCircBuf);
}
}
if (FAILED(hr))
- DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
+ DSLOGREL(("DSound: %s playback failed with %Rhrc\n", fFlush ? "Stopping" : "Pausing", hr));
return hr;
}
@@ -893,40 +912,18 @@ static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamD
AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pStreamDS, E_POINTER);
- HRESULT hr;
- if (pStreamDS->Out.pDSB != NULL)
- {
- DWORD dwStatus;
- hr = directSoundPlayGetStatus(pThis, pStreamDS->Out.pDSB, &dwStatus);
- if (SUCCEEDED(hr))
- {
- if (dwStatus & DSBSTATUS_PLAYING)
- {
- DSLOG(("DSound: Already playing\n"));
- }
- else
- {
- dsoundPlayClearSamples(pThis, pStreamDS);
-
- pStreamDS->Out.fRestartPlayback = true;
- pStreamDS->fEnabled = true;
+ Assert(pStreamDS->fEnabled == false);
- DSLOG(("DSound: Playback started\n"));
+ pStreamDS->fEnabled = true;
+ /* Note: Playing back via DirectSound starts in the notification thread
+ * once enough audio output data is available. */
- /*
- * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlay,
- * because it is necessary to put some samples into the buffer first.
- */
- }
- }
- }
- else
- hr = E_UNEXPECTED;
+ pStreamDS->Out.fFirstPlayback = true;
+ pStreamDS->Out.cUnderruns = 0;
- if (FAILED(hr))
- DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
+ DSLOG(("DSound: Playback started\n"));
- return hr;
+ return S_OK;
}
/*
@@ -940,7 +937,7 @@ static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAMCF
int rc = VINF_SUCCESS;
- LPCGUID pGUID = pThis->cfg.pGuidCapture;
+ LPCGUID pGUID = pThis->Cfg.pGuidCapture;
if (!pGUID)
{
PDSOUNDDEV pDev = NULL;
@@ -1066,33 +1063,30 @@ static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PPDMAUDIO
return hr;
}
-
-static HRESULT directSoundCaptureClose(PDSOUNDSTREAM pStreamDS)
+static HRESULT directSoundCaptureClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
{
+ AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pStreamDS, E_POINTER);
- HRESULT hr = S_OK;
+ LogFlowFuncEnter();
+
+ HRESULT hr = directSoundCaptureStop(pThis, pStreamDS, true /* fFlush */);
+ if (FAILED(hr))
+ return hr;
if ( pStreamDS
&& pStreamDS->In.pDSCB)
{
- DSLOG(("DSound: Closing capturing stream %p, buffer %p\n", pStreamDS, pStreamDS->In.pDSCB));
+ DSLOG(("DSound: Closing capturing stream\n"));
- hr = directSoundCaptureStop(pStreamDS);
- if (SUCCEEDED(hr))
- {
- IDirectSoundCaptureBuffer8_Release(pStreamDS->In.pDSCB);
- pStreamDS->In.pDSCB = NULL;
- }
- else
- DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
+ IDirectSoundCaptureBuffer8_Release(pStreamDS->In.pDSCB);
+ pStreamDS->In.pDSCB = NULL;
}
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
{
@@ -1101,21 +1095,16 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStrea
AssertPtrReturn(pCfgReq, E_POINTER);
AssertPtrReturn(pCfgAcq, E_POINTER);
- DSLOG(("DSound: Opening capturing stream %p: cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pStreamDS,
- pThis->cfg.cbBufferIn,
+ LogFlowFuncEnter();
+
+ Assert(pStreamDS->In.pDSCB == NULL);
+
+ DSLOG(("DSound: Opening capturing stream (uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool)\n",
pCfgReq->Props.uHz,
pCfgReq->Props.cChannels,
pCfgReq->Props.cBits,
pCfgReq->Props.fSigned));
- if (pStreamDS->In.pDSCB != NULL)
- {
- /* Should not happen but be forgiving. */
- DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
- directSoundCaptureClose(pStreamDS);
- }
-
WAVEFORMATEX wfx;
int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
if (RT_FAILURE(rc))
@@ -1129,15 +1118,16 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStrea
do /* To use breaks. */
{
- LPDIRECTSOUNDCAPTUREBUFFER pDSCB = NULL;
-
DSCBUFFERDESC bd;
RT_ZERO(bd);
bd.dwSize = sizeof(bd);
bd.lpwfxFormat = &wfx;
- bd.dwBufferBytes = pThis->cfg.cbBufferIn;
+ bd.dwBufferBytes = DrvAudioHlpMsToBytes(&pCfgReq->Props, pThis->Cfg.msLatencyIn);
+ DSLOG(("DSound: Capture buffer is %ld bytes\n", bd.dwBufferBytes));
+
+ LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
hr = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &bd, &pDSCB, NULL);
if (FAILED(hr))
{
@@ -1183,7 +1173,7 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStrea
hr = IDirectSoundCaptureBuffer8_GetCaps(pStreamDS->In.pDSCB, &bc);
if (FAILED(hr))
{
- DSLOGREL(("Getting capture capabilities failed with %Rhrc\n", hr));
+ DSLOGREL(("DSound: Getting capture capabilities failed with %Rhrc\n", hr));
break;
}
@@ -1211,35 +1201,59 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStrea
DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
bc.dwBufferBytes, pStreamDS->uAlign + 1));
- if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)
- DSLOGREL(("DSound: Capture buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
- bc.dwBufferBytes, pThis->cfg.cbBufferIn));
-
/* Initial state: reading at the initial capture position, no error. */
- pStreamDS->In.offReadPos = offByteReadPos;
- pStreamDS->In.cbBufSize = bc.dwBufferBytes;
+ pStreamDS->In.offReadPos = 0;
+ pStreamDS->cbBufSize = bc.dwBufferBytes;
- pStreamDS->In.hrLastCapture = S_OK;
+ rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Double buffering */);
+ AssertRC(rc);
- DSLOG(("DSound: Opened capturing offReadPos=%RU32, cbBufSize=%RU32\n",
- pStreamDS->In.offReadPos, pStreamDS->In.cbBufSize));
+ /*
+ * Install notification.
+ */
+ LPDIRECTSOUNDNOTIFY8 pNotify;
+ hr = IDirectSoundNotify_QueryInterface(pStreamDS->In.pDSCB, IID_IDirectSoundNotify8, (PVOID *)&pNotify);
+ if (SUCCEEDED(hr))
+ {
+ DSBPOSITIONNOTIFY dsPosNotify[3];
+ RT_ZERO(dsPosNotify);
+
+ dsPosNotify[0].dwOffset = 0;
+ dsPosNotify[0].hEventNotify = pThis->aEvents[DSOUNDEVENT_INPUT];
+
+ dsPosNotify[1].dwOffset = float(pStreamDS->cbBufSize * 0.3);
+ dsPosNotify[1].hEventNotify = pThis->aEvents[DSOUNDEVENT_INPUT];
+
+ dsPosNotify[2].dwOffset = float(pStreamDS->cbBufSize * 0.6);
+ dsPosNotify[2].hEventNotify = pThis->aEvents[DSOUNDEVENT_INPUT];
+
+ hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 3 /* Count */, dsPosNotify);
+ if (FAILED(hr))
+ DSLOGREL(("DSound: Setting capture position notification failed with %Rhrc\n", hr));
+
+ IDirectSoundNotify_Release(pNotify);
+
+ pThis->pDSStrmIn = pStreamDS;
+ }
- pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pThis->cfg.cbBufferIn);
+ pCfgAcq->cFrameBufferHint = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
} while (0);
if (FAILED(hr))
- directSoundCaptureClose(pStreamDS);
+ directSoundCaptureClose(pThis, pStreamDS);
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
-static HRESULT directSoundCaptureStop(PDSOUNDSTREAM pStreamDS)
+static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
{
+ AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pStreamDS, E_POINTER);
+ RT_NOREF(pThis);
+
HRESULT hr = S_OK;
if (pStreamDS->In.pDSCB)
@@ -1254,17 +1268,27 @@ static HRESULT directSoundCaptureStop(PDSOUNDSTREAM pStreamDS)
}
}
+ if (SUCCEEDED(hr))
+ {
+ if ( fFlush
+ && pStreamDS->pCircBuf)
+ {
+ RTCircBufReset(pStreamDS->pCircBuf);
+ }
+ }
+
if (FAILED(hr))
DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
return hr;
}
-
static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, E_POINTER);
+ AssertPtrReturn(pStreamDS, E_POINTER);
+
+ Assert(pStreamDS->fEnabled == false);
HRESULT hr;
if (pStreamDS->In.pDSCB != NULL)
@@ -1283,15 +1307,16 @@ static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStre
}
else
{
- DWORD fFlags = 0;
-#ifndef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- fFlags |= DSCBSTART_LOOPING;
-#endif
+ const DWORD fFlags = DSCBSTART_LOOPING;
+
DSLOG(("DSound: Starting to capture\n"));
hr = IDirectSoundCaptureBuffer8_Start(pStreamDS->In.pDSCB, fFlags);
if (SUCCEEDED(hr))
{
pStreamDS->fEnabled = true;
+
+ pStreamDS->In.offReadPos = 0;
+ pStreamDS->In.cOverruns = 0;
}
else
DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
@@ -1301,14 +1326,10 @@ static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStre
else
hr = E_UNEXPECTED;
- if (SUCCEEDED(hr))
-
-
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID pGUID, LPCWSTR pwszDescription, PDSOUNDDEV *ppDev)
{
AssertPtrReturn(pList, VERR_INVALID_POINTER);
@@ -1335,7 +1356,6 @@ static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID pGUID, LPCWSTR pwszDescripti
return rc;
}
-
static void dsoundDeviceRemove(PDSOUNDDEV pDev)
{
if (pDev)
@@ -1353,7 +1373,6 @@ static void dsoundDeviceRemove(PDSOUNDDEV pDev)
}
}
-
static void dsoundLogDevice(const char *pszType, LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule)
{
char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
@@ -1362,7 +1381,6 @@ static void dsoundLogDevice(const char *pszType, LPGUID pGUID, LPCWSTR pwszDescr
RTStrFree(pszGUID);
}
-
static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
{
PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
@@ -1388,7 +1406,6 @@ static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID pGUID, LPCWSTR pwszDescr
return TRUE;
}
-
static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
{
PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
@@ -1411,7 +1428,6 @@ static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescri
return TRUE;
}
-
/**
* Does a (Re-)enumeration of the host's playback + capturing devices.
*
@@ -1466,7 +1482,6 @@ static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx
return rc;
}
-
/**
* Updates this host driver's internal status, according to the global, overall input/output
* state and all connected (native) audio streams.
@@ -1491,17 +1506,16 @@ static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDC
int rc = dsoundDevicesEnumerate(pThis, &cbCtx, fEnum);
if (RT_SUCCESS(rc))
{
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
+#if 0
if ( pThis->fEnabledOut != RT_BOOL(cbCtx.cDevOut)
|| pThis->fEnabledIn != RT_BOOL(cbCtx.cDevIn))
{
/** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
* let the connector know that something has changed within the host backend. */
}
-#else
+#endif
pThis->fEnabledOut = RT_BOOL(cbCtx.cDevOut);
pThis->fEnabledIn = RT_BOOL(cbCtx.cDevIn);
-#endif
Cfg.cMaxStreamsIn = UINT32_MAX;
Cfg.cMaxStreamsOut = UINT32_MAX;
@@ -1513,25 +1527,26 @@ static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDC
LogFlowFuncLeaveRC(rc);
}
-
static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
{
dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
}
-
static int dsoundCreateStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
{
LogFlowFunc(("pStreamDS=%p, pCfgReq=%p\n", pStreamDS, pCfgReq));
+ pStreamDS->cbBufSize = 0;
+
pStreamDS->Out.pDSB = NULL;
pStreamDS->Out.offWritePos = 0;
pStreamDS->Out.offPlayCursorLastPlayed = 0;
pStreamDS->Out.offPlayCursorLastPending = 0;
pStreamDS->Out.cbWritten = 0;
- pStreamDS->Out.fRestartPlayback = true;
- pStreamDS->Out.cbBufSize = 0;
+ pStreamDS->Out.cbPlayed = 0;
+ pStreamDS->Out.fFirstPlayback = true;
+ pStreamDS->Out.tsLastPlayMs = 0;
int rc = VINF_SUCCESS;
@@ -1554,41 +1569,32 @@ static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
switch (enmStreamCmd)
{
case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
{
hr = directSoundPlayStart(pThis, pStreamDS);
if (FAILED(hr))
- {
- hr = directSoundPlayClose(pThis, pStreamDS);
- if (SUCCEEDED(hr))
- {
- PDMAUDIOSTREAMCFG CfgAcq;
- hr = directSoundPlayOpen(pThis, pStreamDS, pStreamDS->pCfg /* pCfqReq */, &CfgAcq);
- if (SUCCEEDED(hr))
- {
- DrvAudioHlpStreamCfgFree(pStreamDS->pCfg);
-
- pStreamDS->pCfg = DrvAudioHlpStreamCfgDup(&CfgAcq);
- AssertPtr(pStreamDS->pCfg);
+ rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */
+ break;
+ }
- /** @todo What to do if the format has changed? */
- }
- }
- if (SUCCEEDED(hr))
- hr = directSoundPlayStart(pThis, pStreamDS);
+ case PDMAUDIOSTREAMCMD_RESUME:
+ {
+ hr = directSoundPlayStart(pThis, pStreamDS);
+ if (SUCCEEDED(hr))
+ {
+ BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
+ RT_NOREF(fRc);
+ Assert(fRc);
}
if (FAILED(hr))
- rc = VERR_NOT_SUPPORTED;
+ rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
case PDMAUDIOSTREAMCMD_PAUSE:
{
- AssertPtr(pThis->pDS);
-
- hr = directSoundPlayStop(pThis, pStreamDS);
+ hr = directSoundPlayStop(pThis, pStreamDS, enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE /* fFlush */);
if (FAILED(hr))
rc = VERR_NOT_SUPPORTED;
break;
@@ -1606,7 +1612,6 @@ static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
return rc;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
*/
@@ -1626,126 +1631,41 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface,
uint32_t cbWrittenTotal = 0;
-#ifdef DEBUG_andy
- LogFlowFuncEnter();
-#endif
+ uint8_t *pbBuf = (uint8_t *)pvBuf;
+ PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
- do /* to use 'break' */
+ uint32_t cbToPlay = RT_MIN(cxBuf, (uint32_t)RTCircBufFree(pCircBuf));
+ while (cbToPlay)
{
- AssertPtr(pStreamDS->pCfg);
- PPDMAUDIOPCMPROPS pProps = &pStreamDS->pCfg->Props;
+ void *pvChunk;
+ size_t cbChunk;
+ RTCircBufAcquireWriteBlock(pCircBuf, cbToPlay, &pvChunk, &cbChunk);
- DWORD cbFree;
- rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree);
- if (RT_FAILURE(rc))
- break;
-
- if (pStreamDS->Out.fRestartPlayback == false)
+ if (cbChunk)
{
- DWORD offPlayCursor, offWriteCursor;
- HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor);
- if (SUCCEEDED(hr))
- {
- uint32_t cbPending;
- if (pStreamDS->Out.offPlayCursorLastPlayed <= offPlayCursor)
- cbPending = offPlayCursor - pStreamDS->Out.offPlayCursorLastPlayed;
- else
- cbPending = pStreamDS->Out.cbBufSize - pStreamDS->Out.offPlayCursorLastPlayed + offPlayCursor;
-
- pStreamDS->Out.cbWritten -= RT_MIN(pStreamDS->Out.cbWritten, cbPending);
- pStreamDS->Out.offPlayCursorLastPlayed = offPlayCursor;
- }
- }
+ memcpy(pvChunk, pbBuf, cbChunk);
- /*
- * Check for full buffer, do not allow the offPlayWritePos to catch cbPlayPos during playback,
- * i.e. always leave a free space for 1 audio sample.
- */
- const DWORD cbSample = PDMAUDIOPCMPROPS_F2B(pProps, 1);
- if (cbFree < cbSample)
- break;
- Assert(cbFree >= cbSample);
- cbFree -= cbSample;
-
- uint32_t cbLive = cxBuf;
-
- /* Do not write more than available space in the DirectSound playback buffer. */
- cbLive = RT_MIN(cbFree, cbLive);
- cbLive &= ~pStreamDS->uAlign;
-
- if (!cbLive)
- break;
+ pbBuf += cbChunk;
+ Assert(cbToPlay >= cbChunk);
+ cbToPlay -= (uint32_t)cbChunk;
- LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;
- AssertPtr(pDSB);
-
- PVOID pv1, pv2;
- DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbLive,
- &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
- if (FAILED(hr))
- {
- rc = VERR_ACCESS_DENIED;
- break;
+ cbWrittenTotal += (uint32_t)cbChunk;
}
- AssertPtr(pv1);
- Assert(cb1);
-
- memcpy(pv1, pvBuf, cb1);
- cbWrittenTotal = cb1;
-
- if (pv2 && cb2) /* Buffer wrap-around? Write second part. */
- {
- memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2);
- cbWrittenTotal += cb2;
- }
-
- Assert(cbLive == cb1 + cb2);
-
- directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
-
- pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cbWrittenTotal) % pStreamDS->Out.cbBufSize;
- pStreamDS->Out.cbWritten += cbWrittenTotal;
+ RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
+ }
- DSLOGF(("DSound: %RU32/%RU32, buffer write pos %ld, rc=%Rrc\n",
- cbWrittenTotal, cbLive, pStreamDS->Out.offWritePos, rc));
+ Assert(cbWrittenTotal <= cxBuf);
- if (pStreamDS->Out.fRestartPlayback)
- {
- /*
- * The playback has been just started.
- * Some samples of the new sound have been copied to the buffer
- * and it can start playing.
- */
- pStreamDS->Out.fRestartPlayback = false;
-
- DWORD fFlags = 0;
-#ifndef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- fFlags |= DSCBSTART_LOOPING;
-#endif
- for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
- {
- hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, fFlags);
- if ( SUCCEEDED(hr)
- || hr != DSERR_BUFFERLOST)
- break;
- else
- {
- LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
- }
- }
-
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
- }
+ pStreamDS->Out.cbWritten += cbWrittenTotal;
- } while (0);
+ if ( pStreamDS->Out.fFirstPlayback
+ && pStreamDS->Out.cbWritten >= pStreamDS->cbBufSize)
+ {
+ BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
+ RT_NOREF(fRc);
+ Assert(fRc);
+ }
if (RT_SUCCESS(rc))
{
@@ -1758,12 +1678,19 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface,
return rc;
}
-
static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDSTREAM pStream)
{
PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
- directSoundPlayClose(pThis, pStreamDS);
+ LogFlowFuncEnter();
+
+ HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
+ if (SUCCEEDED(hr))
+ {
+ hr = directSoundPlayClose(pThis, pStreamDS);
+ if (FAILED(hr))
+ return VERR_GENERAL_FAILURE; /** @todo Fix. */
+ }
return VINF_SUCCESS;
}
@@ -1775,10 +1702,11 @@ static int dsoundCreateStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
pStreamDS, pCfgReq, DrvAudioHlpRecSrcToStr(pCfgReq->DestSource.Source)));
/* Init the stream structure and save relevant information to it. */
- pStreamDS->In.offReadPos = 0;
- pStreamDS->In.cbBufSize = 0;
- pStreamDS->In.pDSCB = NULL;
- pStreamDS->In.hrLastCapture = S_OK;
+ pStreamDS->cbBufSize = 0;
+
+ pStreamDS->In.pDSCB = NULL;
+ pStreamDS->In.offReadPos = 0;
+ pStreamDS->In.cOverruns = 0;
int rc = VINF_SUCCESS;
@@ -1806,7 +1734,7 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
hr = directSoundCaptureStart(pThis, pStreamDS);
if (FAILED(hr))
{
- hr = directSoundCaptureClose(pStreamDS);
+ hr = directSoundCaptureClose(pThis, pStreamDS);
if (SUCCEEDED(hr))
{
PDMAUDIOSTREAMCFG CfgAcq;
@@ -1835,7 +1763,8 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
{
AssertPtr(pThis->pDSC);
- directSoundCaptureStop(pStreamDS);
+ directSoundCaptureStop(pThis, pStreamDS,
+ enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE /* fFlush */);
/* Return success in any case, as stopping the capture can fail if
* the capture buffer is not around anymore.
@@ -1856,7 +1785,6 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
return rc;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
*/
@@ -1872,95 +1800,27 @@ int drvHostDSoundStreamCapture(PPDMIHOSTAUDIO pInterface,
PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
- LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pStreamDS->In.pDSCB;
- AssertPtr(pDSCB);
-
int rc = VINF_SUCCESS;
uint32_t cbReadTotal = 0;
- do
+ uint32_t cbToRead = RT_MIN((uint32_t)RTCircBufUsed(pStreamDS->pCircBuf), cxBuf);
+ while (cbToRead)
{
- if (pDSCB == NULL)
- {
- rc = VERR_NOT_AVAILABLE;
- break;
- }
+ void *pvChunk;
+ size_t cbChunk;
+ RTCircBufAcquireReadBlock(pStreamDS->pCircBuf, cbToRead, &pvChunk, &cbChunk);
- /* Get DirectSound capture position in bytes. */
- DWORD offCurPos;
- HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &offCurPos);
- if (FAILED(hr))
+ if (cbChunk)
{
- if (hr != pStreamDS->In.hrLastCapture)
- {
- DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
- pStreamDS->In.hrLastCapture = hr;
- }
-
- rc = VERR_NOT_AVAILABLE;
- break;
- }
-
- pStreamDS->In.hrLastCapture = hr;
-
- if (offCurPos & pStreamDS->uAlign)
- DSLOGF(("DSound: Misaligned capture read position %ld (alignment: %RU32)\n",
- offCurPos, pStreamDS->uAlign + 1));
-
- /* Number of samples available in the DirectSound capture buffer. */
- DWORD cbToCapture = dsoundRingDistance(offCurPos, pStreamDS->In.offReadPos, pStreamDS->In.cbBufSize);
- if (cbToCapture == 0)
- break;
-
- if (cxBuf == 0)
- {
- DSLOGF(("DSound: Capture buffer full\n"));
- break;
+ memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk);
+ cbReadTotal += (uint32_t)cbChunk;
+ Assert(cbToRead >= cbChunk);
+ cbToRead -= (uint32_t)cbChunk;
}
- DSLOGF(("DSound: Capture cxBuf=%RU32, offCurPos=%ld, offReadPos=%ld, cbToCapture=%ld\n",
- cxBuf, offCurPos, pStreamDS->In.offReadPos, cbToCapture));
-
- /* No need to fetch more samples than mix buffer can receive. */
- cbToCapture = RT_MIN(cbToCapture, cxBuf);
-
- /* Lock relevant range in the DirectSound capture buffer. */
- PVOID pv1, pv2;
- DWORD cb1, cb2;
- hr = directSoundCaptureLock(pStreamDS,
- pStreamDS->In.offReadPos, /* dwOffset */
- cbToCapture, /* dwBytes */
- &pv1, &pv2, &cb1, &cb2,
- 0 /* dwFlags */);
- if (FAILED(hr))
- {
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- if (pv1 && cb1)
- {
- memcpy((uint8_t *)pvBuf + cbReadTotal, pv1, cb1);
- cbReadTotal += cb1;
- }
-
- if (pv2 && cb2)
- {
- memcpy((uint8_t *)pvBuf + cbReadTotal, pv2, cb2);
- cbReadTotal += cb2;
- }
-
- directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
-
- if (RT_SUCCESS(rc))
- {
- pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cbReadTotal)
- % pStreamDS->In.cbBufSize;
- DSLOGF(("DSound: Captured %ld bytes (%RU32 total)\n", cbToCapture, cbReadTotal));
- }
-
- } while (0);
+ RTCircBufReleaseReadBlock(pStreamDS->pCircBuf, cbChunk);
+ }
if (RT_SUCCESS(rc))
{
@@ -1973,14 +1833,15 @@ int drvHostDSoundStreamCapture(PPDMIHOSTAUDIO pInterface,
return rc;
}
-static int dsoundDestroyStreamIn(PDSOUNDSTREAM pStreamDS)
+static int dsoundDestroyStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
{
- directSoundCaptureClose(pStreamDS);
+ LogFlowFuncEnter();
+
+ directSoundCaptureClose(pThis, pStreamDS);
return VINF_SUCCESS;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
*/
@@ -1996,8 +1857,6 @@ int drvHostDSoundGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBacke
return VINF_SUCCESS;
}
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
-
static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
@@ -2010,13 +1869,14 @@ static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
/* Set the notification event so that the thread is being notified. */
BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
+ RT_NOREF(fRc);
Assert(fRc);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pvUser)
+static DECLCALLBACK(int) dsoundThread(RTTHREAD hThreadSelf, void *pvUser)
{
PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser;
AssertPtr(pThis);
@@ -2027,8 +1887,10 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
int rc = RTThreadUserSignal(hThreadSelf);
AssertRC(rc);
- do
+ for (;;)
{
+ RTCritSectEnter(&pThis->CritSect);
+
HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
DWORD cEvents = 0;
for (uint8_t i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
@@ -2038,9 +1900,12 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
}
Assert(cEvents);
- LogFlowFunc(("Waiting: cEvents=%ld\n", cEvents));
+ RTCritSectLeave(&pThis->CritSect);
DWORD dwObj = WaitForMultipleObjects(cEvents, aEvents, FALSE /* bWaitAll */, INFINITE);
+
+ RTCritSectEnter(&pThis->CritSect);
+
switch (dwObj)
{
case WAIT_FAILED:
@@ -2055,49 +1920,225 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
break;
}
- default:
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ case WAIT_OBJECT_0 + 2:
+ case WAIT_OBJECT_0 + 3:
+ case WAIT_OBJECT_0 + 4:
{
- dwObj = WAIT_OBJECT_0 + cEvents - 1;
- if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_NOTIFY])
+ dwObj -= WAIT_OBJECT_0;
+
+ if (dwObj == DSOUNDEVENT_NOTIFY)
{
- LogFlowFunc(("Notify\n"));
+ Log3Func(("Notify\n"));
}
- else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_INPUT])
+ else if (dwObj == DSOUNDEVENT_INPUT)
{
+ PDSOUNDSTREAM pStreamDS = pThis->pDSStrmIn;
+
+ if ( !pStreamDS
+ || !pStreamDS->fEnabled)
+ {
+ Log3Func(("Skipping capture\n"));
+ break;
+ }
+ LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pStreamDS->In.pDSCB;
+ AssertPtr(pDSCB);
+
+ DWORD offCaptureCursor;
+ HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &offCaptureCursor);
+ if (FAILED(hr))
+ break;
+
+ DWORD cbUsed = dsoundRingDistance(offCaptureCursor, pStreamDS->In.offReadPos, pStreamDS->cbBufSize);
+
+ PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
+ AssertPtr(pCircBuf);
+
+ uint32_t cbFree = (uint32_t)RTCircBufFree(pCircBuf);
+ if ( !cbFree
+ || pStreamDS->In.cOverruns < 32) /** @todo Make this configurable. */
+ {
+ DSLOG(("DSound: Warning: Capture buffer full, skipping to record data (%RU32 bytes)\n", cbUsed));
+ pStreamDS->In.cOverruns++;
+ }
+
+ DWORD cbToCapture = RT_MIN(cbUsed, cbFree);
+
+ Log3Func(("cbUsed=%ld, cbToCapture=%ld\n", cbUsed, cbToCapture));
+
+ while (cbToCapture)
+ {
+ void *pvBuf;
+ size_t cbBuf;
+ RTCircBufAcquireWriteBlock(pCircBuf, cbToCapture, &pvBuf, &cbBuf);
+
+ if (cbBuf)
+ {
+ PVOID pv1, pv2;
+ DWORD cb1, cb2;
+ hr = directSoundCaptureLock(pStreamDS, pStreamDS->In.offReadPos, (DWORD)cbBuf,
+ &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
+ if (FAILED(hr))
+ break;
+
+ AssertPtr(pv1);
+ Assert(cb1);
+
+ memcpy(pvBuf, pv1, cb1);
+
+ if (pv2 && cb2) /* Buffer wrap-around? Write second part. */
+ memcpy((uint8_t *)pvBuf + cb1, pv2, cb2);
+
+ directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
+
+ pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cb1 + cb2) % pStreamDS->cbBufSize;
+
+ Assert(cbToCapture >= cbBuf);
+ cbToCapture -= (uint32_t)cbBuf;
+ }
+
+#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
+ if (cbBuf)
+ {
+ RTFILE fh;
+ int rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "dsoundCapture.pcm",
+ RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+ if (RT_SUCCESS(rc2))
+ {
+ RTFileWrite(fh, pvBuf, cbBuf, NULL);
+ RTFileClose(fh);
+ }
+ }
+#endif
+ RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
+ }
}
- else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])
+ else if (dwObj == DSOUNDEVENT_OUTPUT)
{
- DWORD cbFree;
- rc = dsoundGetFreeOut(pThis->pDSStream, &cbFree);
- if ( RT_SUCCESS(rc)
- && cbFree)
+ PDSOUNDSTREAM pStreamDS = pThis->pDSStrmOut;
+
+ if ( !pStreamDS
+ || !pStreamDS->fEnabled)
{
- PDMAUDIOCBDATA_DATA_OUTPUT Out;
- Out.cbInFree = cbFree;
- Out.cbOutWritten = 0;
+ Log3Func(("Skipping playback\n"));
+ break;
+ }
- while (!Out.cbOutWritten)
+ LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;
+ AssertPtr(pDSB);
+
+ HRESULT hr;
+
+ DWORD offPlayCursor, offWriteCursor;
+ hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);
+ if (FAILED(hr))
+ break;
+
+ DWORD cbFree, cbRemaining;
+ if (pStreamDS->Out.fFirstPlayback)
+ {
+ cbRemaining = 0;
+ cbFree = dsoundRingDistance(pStreamDS->Out.offWritePos, 0, pStreamDS->cbBufSize);
+ }
+ else
+ {
+ cbFree = dsoundRingDistance(offPlayCursor, pStreamDS->Out.offWritePos, pStreamDS->cbBufSize);
+ cbRemaining = dsoundRingDistance(pStreamDS->Out.offWritePos, offPlayCursor, pStreamDS->cbBufSize);
+ }
+
+ PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
+ AssertPtr(pCircBuf);
+
+ DWORD cbUsed = (uint32_t)RTCircBufUsed(pCircBuf);
+ DWORD cbToPlay = RT_MIN(cbFree, cbUsed);
+
+ if ( !cbUsed
+ && pStreamDS->Out.cbWritten
+ && pStreamDS->Out.cUnderruns < 32) /** @todo Make this configurable. */
+ {
+ //DSLOG(("DSound: Warning: No more playback data available within time (%RU32 bytes free)\n", cbFree));
+ Log3Func(("Underrun (cbFree=%ld, cbRemaining=%ld, cbUsed=%ld, cbToPlay=%ld, offPlay=%ld, offWrite=%ld)\n",
+ cbFree, cbRemaining, cbUsed, cbToPlay, offPlayCursor, offWriteCursor));
+ pStreamDS->Out.cUnderruns++;
+ }
+
+ while (cbToPlay)
+ {
+ void *pvBuf;
+ size_t cbBuf;
+ RTCircBufAcquireReadBlock(pCircBuf, cbToPlay, &pvBuf, &cbBuf);
+
+ if (cbBuf)
+ {
+ PVOID pv1, pv2;
+ DWORD cb1, cb2;
+ hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, (DWORD)cbBuf,
+ &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
+ if (FAILED(hr))
+ break;
+
+ AssertPtr(pv1);
+ Assert(cb1);
+
+ memcpy(pv1, pvBuf, cb1);
+
+ if (pv2 && cb2) /* Buffer wrap-around? Write second part. */
+ memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2);
+
+ directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
+
+ pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;
+
+ Assert(cbToPlay >= cbBuf);
+ cbToPlay -= (uint32_t)cbBuf;
+
+ pStreamDS->Out.cbPlayed += cb1 + cb2;
+ }
+
+ RTCircBufReleaseReadBlock(pCircBuf, cbBuf);
+ }
+
+ if ( pStreamDS->Out.fFirstPlayback
+ && RTCircBufUsed(pCircBuf) >= pStreamDS->cbBufSize)
+ {
+ DWORD fFlags = DSCBSTART_LOOPING;
+
+ for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
- rc = pThis->pUpIAudioConnector->pfnCallback(pThis->pUpIAudioConnector,
- PDMAUDIOCALLBACKTYPE_OUTPUT, &Out, sizeof(Out));
- if (RT_FAILURE(rc))
+ hr = IDirectSoundBuffer8_Play(pDSB, 0, 0, fFlags);
+ if ( SUCCEEDED(hr)
+ || hr != DSERR_BUFFERLOST)
break;
- RTThreadSleep(100);
+ else
+ {
+ LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
+ directSoundPlayRestore(pThis, pDSB);
+ }
}
- LogFlowFunc(("Output: cbBuffer=%ld, cbFree=%ld, cbWritten=%RU32, rc=%Rrc\n",
- cbBuffer, cbFree, Out.cbOutWritten, rc));
+ if (SUCCEEDED(hr))
+ {
+ DSLOG(("DSound: Started playing output\n"));
+ pStreamDS->Out.fFirstPlayback = false;
+ }
}
}
break;
}
+
+ default:
+ AssertFailed();
+ break;
}
+ RTCritSectLeave(&pThis->CritSect);
+
if (pThis->fShutdown)
break;
- } while (RT_SUCCESS(rc));
+ } /* for */
pThis->fStopped = true;
@@ -2105,9 +2146,6 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
return rc;
}
-#endif /* VBOX_WITH_AUDIO_DEVICE_CALLBACKS */
-
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
*/
@@ -2117,7 +2155,6 @@ void drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
LogFlowFuncEnter();
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
int rc = dsoundNotifyThread(pThis, true /* fShutdown */);
AssertRC(rc);
@@ -2127,19 +2164,15 @@ void drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
Assert(pThis->fStopped);
- if (pThis->aEvents[DSOUNDEVENT_NOTIFY])
+ for (int i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
{
- CloseHandle(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
- pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL;
+ if (pThis->aEvents[i])
+ CloseHandle(pThis->aEvents[i]);
}
-#else
- RT_NOREF_PV(pThis);
-#endif
LogFlowFuncLeave();
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
*/
@@ -2157,15 +2190,17 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
{
IDirectSound_Release(pDirectSound);
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- /* Create notification event. */
- pThis->aEvents[DSOUNDEVENT_NOTIFY] = CreateEvent(NULL /* Security attribute */,
- FALSE /* bManualReset */, FALSE /* bInitialState */,
- NULL /* lpName */);
- Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL);
+ /* Create notification events. */
+ for (int i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
+ {
+ pThis->aEvents[i] = CreateEvent(NULL /* Security attribute */,
+ FALSE /* bManualReset */, FALSE /* bInitialState */,
+ NULL /* lpName */);
+ Assert(pThis->aEvents[i] != NULL);
+ }
/* Start notification thread. */
- rc = RTThreadCreate(&pThis->Thread, dsoundNotificationThread,
+ rc = RTThreadCreate(&pThis->Thread, dsoundThread,
pThis /*pvUser*/, 0 /*cbStack*/,
RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dsoundNtfy");
if (RT_SUCCESS(rc))
@@ -2175,11 +2210,8 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
if (RT_FAILURE(rc))
DSLOGREL(("DSound: Waiting for thread to initialize failed with rc=%Rrc\n", rc));
}
- else
+ else
DSLOGREL(("DSound: Creating thread failed with rc=%Rrc\n", rc));
-#else
- rc = VINF_SUCCESS;
-#endif
dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
}
@@ -2193,7 +2225,6 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
return rc;
}
-
static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID *pUuid)
{
LPCGUID pGuid = NULL;
@@ -2214,29 +2245,23 @@ static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID
return pGuid;
}
-
static int dsoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
{
- unsigned int uBufsizeOut, uBufsizeIn;
-
- CFGMR3QueryUIntDef(pCfg, "BufsizeOut", &uBufsizeOut, _16K);
- CFGMR3QueryUIntDef(pCfg, "BufsizeIn", &uBufsizeIn, _16K);
- pThis->cfg.cbBufferOut = uBufsizeOut;
- pThis->cfg.cbBufferIn = uBufsizeIn;
+ CFGMR3QueryUIntDef(pCfg, "LatencyMsIn", &pThis->Cfg.msLatencyIn, DRV_DSOUND_DEFAULT_LATENCY_MS_IN);
+ CFGMR3QueryUIntDef(pCfg, "LatencyMsOut", &pThis->Cfg.msLatencyOut, DRV_DSOUND_DEFAULT_LATENCY_MS_OUT);
- pThis->cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->cfg.uuidPlay);
- pThis->cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->cfg.uuidCapture);
+ pThis->Cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->Cfg.uuidPlay);
+ pThis->Cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->Cfg.uuidCapture);
- DSLOG(("DSound: Configuration cbBufferIn=%ld, cbBufferOut=%ld, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n",
- pThis->cfg.cbBufferIn,
- pThis->cfg.cbBufferOut,
- &pThis->cfg.uuidPlay,
- &pThis->cfg.uuidCapture));
+ DSLOG(("DSound: Configuration: Input latency = %ums, Output latency = %ums, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n",
+ pThis->Cfg.msLatencyIn,
+ pThis->Cfg.msLatencyOut,
+ &pThis->Cfg.uuidPlay,
+ &pThis->Cfg.uuidCapture));
return VINF_SUCCESS;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
*/
@@ -2248,7 +2273,6 @@ static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDSoundGetStatus(PPDMIHOSTAUDIO pI
return PDMAUDIOBACKENDSTS_RUNNING;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
*/
@@ -2272,14 +2296,17 @@ static DECLCALLBACK(int) drvHostDSoundStreamCreate(PPDMIHOSTAUDIO pInterface, PP
if (RT_SUCCESS(rc))
{
pStreamDS->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq);
- if (!pStreamDS->pCfg)
+ if (pStreamDS->pCfg)
+ {
+ rc = RTCritSectInit(&pStreamDS->CritSect);
+ }
+ else
rc = VERR_NO_MEMORY;
}
return rc;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
*/
@@ -2296,12 +2323,14 @@ static DECLCALLBACK(int) drvHostDSoundStreamDestroy(PPDMIHOSTAUDIO pInterface, P
int rc;
if (pStreamDS->pCfg->enmDir == PDMAUDIODIR_IN)
- rc = dsoundDestroyStreamIn(pStreamDS);
+ rc = dsoundDestroyStreamIn(pThis, pStreamDS);
else
rc = dsoundDestroyStreamOut(pThis, pStreamDS);
if (RT_SUCCESS(rc))
{
+ rc = RTCritSectDelete(&pStreamDS->CritSect);
+
DrvAudioHlpStreamCfgFree(pStreamDS->pCfg);
pStreamDS->pCfg = NULL;
}
@@ -2309,7 +2338,6 @@ static DECLCALLBACK(int) drvHostDSoundStreamDestroy(PPDMIHOSTAUDIO pInterface, P
return rc;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
*/
@@ -2334,7 +2362,6 @@ static DECLCALLBACK(int) drvHostDSoundStreamControl(PPDMIHOSTAUDIO pInterface,
return rc;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
*/
@@ -2345,13 +2372,15 @@ static DECLCALLBACK(uint32_t) drvHostDSoundStreamGetReadable(PPDMIHOSTAUDIO pInt
PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
- if (pStreamDS->fEnabled)
- return UINT32_MAX;
+ if ( pStreamDS->fEnabled
+ && pStreamDS->pCircBuf)
+ {
+ return (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);
+ }
return 0;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
*/
@@ -2360,25 +2389,14 @@ static DECLCALLBACK(uint32_t) drvHostDSoundStreamGetWritable(PPDMIHOSTAUDIO pInt
AssertPtrReturn(pInterface, PDMAUDIOSTREAMSTS_FLAG_NONE);
AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAG_NONE);
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
if (pStreamDS->fEnabled)
- {
- DWORD cbFree;
- int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree);
- if ( RT_SUCCESS(rc)
- && cbFree)
- {
- Log3Func(("cbFree=%ld\n", cbFree));
- return (uint32_t)cbFree;
- }
- }
+ return (uint32_t)RTCircBufFree(pStreamDS->pCircBuf);
return 0;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
*/
@@ -2387,52 +2405,41 @@ static DECLCALLBACK(uint32_t) drvHostDSoundStreamGetPending(PPDMIHOSTAUDIO pInte
RT_NOREF(pInterface);
AssertPtrReturn(pStream, 0);
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
if (pStreamDS->pCfg->enmDir == PDMAUDIODIR_OUT)
{
- DWORD dwStatus;
- HRESULT hr = directSoundPlayGetStatus(pThis, pStreamDS->Out.pDSB, &dwStatus);
- if (hr != DS_OK)
- return 0;
-
- if (!(dwStatus & DSBSTATUS_PLAYING))
- return 0;
-
- DWORD offPlayCursor, offWriteCursor;
- hr = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor);
- if (SUCCEEDED(hr))
- {
- uint32_t cbPending;
- if (pStreamDS->Out.offPlayCursorLastPending <= offPlayCursor)
- cbPending = offPlayCursor - pStreamDS->Out.offPlayCursorLastPending;
- else
- cbPending = pStreamDS->Out.cbBufSize - pStreamDS->Out.offPlayCursorLastPending + offPlayCursor;
-
- pStreamDS->Out.cbWritten -= RT_MIN(pStreamDS->Out.cbWritten, cbPending);
- pStreamDS->Out.offPlayCursorLastPending = offPlayCursor;
-
- LogFunc(("offPlayCursor=%RU32, offWriteCursor=%RU32\n", offPlayCursor, offWriteCursor));
- LogFunc(("offPlayWritePos=%RU32, cbWritten=%RU64, cbPending=%RU32\n",
- pStreamDS->Out.offWritePos, pStreamDS->Out.cbWritten, cbPending));
-
- /*
- * As we operate a DirectSound secondary *streaming* buffer which loops over
- * the data repeatedly until stopped, we have to make at least an estimate when we're actually
- * done playing the written data on the host.
- */
- return pStreamDS->Out.cbWritten;
+ uint32_t cbPending = 0;
+
+ /* Any uncommitted data left? */
+ if (pStreamDS->pCircBuf)
+ cbPending = (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);
+
+ /* Check if we have committed data which still needs to be played by
+ * by DirectSound's streaming buffer. */
+ if (!cbPending)
+ {
+ const uint64_t tsNowMs = RTTimeMilliTS();
+ if (pStreamDS->Out.tsLastPlayMs == 0)
+ pStreamDS->Out.tsLastPlayMs = tsNowMs;
+
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+ const uint64_t diffLastPlayMs = tsNowMs - pStreamDS->Out.tsLastPlayMs;
+ const uint64_t msThreshold = pThis->Cfg.msLatencyOut;
+
+ Log2Func(("diffLastPlayMs=%RU64ms\n", diffLastPlayMs));
+
+ cbPending = (diffLastPlayMs >= msThreshold) ? 0 : 1;
}
- else
- LogFunc(("Failed with %Rhrc\n", hr));
+
+ return cbPending;
}
/* Note: For input streams we never have pending data left. */
return 0;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
*/
@@ -2461,7 +2468,6 @@ static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundStreamGetStatus(PPDMIHOSTAUD
return strmSts;
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
*/
@@ -2470,8 +2476,6 @@ static DECLCALLBACK(int) drvHostDSoundStreamIterate(PPDMIHOSTAUDIO pInterface, P
AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- LogFlowFuncEnter();
-
/* Nothing to do here for DSound. */
return VINF_SUCCESS;
}
@@ -2573,7 +2577,6 @@ static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
LogFlowFuncLeave();
}
-
/**
* @callback_method_impl{FNPDMDRVCONSTRUCT,
* Construct a DirectSound Audio driver instance.}
@@ -2606,22 +2609,10 @@ static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
#ifdef VBOX_WITH_AUDIO_CALLBACKS
/* This backend supports host audio callbacks. */
- pThis->IHostAudio.pfnSetCallback = drvHostDSoundSetCallback;
+ pThis->IHostAudio.pfnSetCallback = drvHostDSoundSetCallback;
pThis->pfnCallback = NULL;
#endif
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
- /*
- * Get the IAudioConnector interface of the above driver/device.
- */
- pThis->pUpIAudioConnector = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
- if (!pThis->pUpIAudioConnector)
- {
- AssertMsgFailed(("Configuration error: No audio connector interface above!\n"));
- return VERR_PDM_MISSING_INTERFACE_ABOVE;
- }
-#endif
-
/*
* Init the static parts.
*/
@@ -2630,13 +2621,10 @@ static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
pThis->fEnabledIn = false;
pThis->fEnabledOut = false;
-#ifdef VBOX_WITH_AUDIO_DEVICE_CALLBACKS
pThis->fStopped = false;
pThis->fShutdown = false;
RT_ZERO(pThis->aEvents);
- pThis->cEvents = 0;
-#endif
int rc = VINF_SUCCESS;
diff --git a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
index d2c5001..d0d63e6 100644
--- a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2017 Oracle Corporation
+ * Copyright (C) 2006-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -93,6 +93,10 @@ typedef struct DRVHOSTPULSEAUDIO
/** Error count for not flooding the release log.
* Specify UINT32_MAX for unlimited logging. */
uint32_t cLogErrors;
+ /** The stream (base) name; needed for distinguishing
+ * streams in the PulseAudio mixer controls if multiple
+ * VMs are running at the same time. */
+ char szStreamName[64];
} DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO;
typedef struct PULSEAUDIOSTREAM
@@ -757,8 +761,14 @@ static int paCreateStreamOut(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStream
LogFunc(("BufAttr tlength=%RU32, maxLength=%RU32, minReq=%RU32\n",
pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq));
+ Assert(pCfgReq->enmDir == PDMAUDIODIR_OUT);
+
+ char szName[256];
+ RTStrPrintf2(szName, sizeof(szName), "VirtualBox %s [%s]",
+ DrvAudioHlpPlaybackDstToStr(pCfgReq->DestSource.Dest), pThis->szStreamName);
+
/* Note that the struct BufAttr is updated to the obtained values after this call! */
- int rc = paStreamOpen(pThis, pStreamPA, false /* fIn */, "PulseAudio (Out)");
+ int rc = paStreamOpen(pThis, pStreamPA, false /* fIn */, szName);
if (RT_FAILURE(rc))
return rc;
@@ -799,8 +809,14 @@ static int paCreateStreamIn(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStream
pStreamPA->BufAttr.fragsize = (pa_bytes_per_second(&pStreamPA->SampleSpec) * s_pulseCfg.buffer_msecs_in) / 1000;
pStreamPA->BufAttr.maxlength = (pStreamPA->BufAttr.fragsize * 3) / 2;
+ Assert(pCfgReq->enmDir == PDMAUDIODIR_IN);
+
+ char szName[256];
+ RTStrPrintf2(szName, sizeof(szName), "VirtualBox %s [%s]",
+ DrvAudioHlpRecSrcToStr(pCfgReq->DestSource.Source), pThis->szStreamName);
+
/* Note: Other members of BufAttr are ignored for record streams. */
- int rc = paStreamOpen(pThis, pStreamPA, true /* fIn */, "PulseAudio (In)");
+ int rc = paStreamOpen(pThis, pStreamPA, true /* fIn */, szName);
if (RT_FAILURE(rc))
return rc;
@@ -1576,7 +1592,6 @@ static DECLCALLBACK(uint32_t) drvHostPulseAudioStreamGetWritable(PPDMIHOSTAUDIO
}
-
/**
* @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
*/
@@ -1664,6 +1679,9 @@ static DECLCALLBACK(int) drvHostPulseAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNOD
/* IHostAudio */
PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostPulseAudio);
+ int rc2 = CFGMR3QueryString(pCfg, "StreamName", pThis->szStreamName, sizeof(pThis->szStreamName));
+ AssertMsgRCReturn(rc2, ("Confguration error: No/bad \"StreamName\" value, rc=%Rrc\n", rc2), rc2);
+
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/Audio/HDACodec.cpp b/src/VBox/Devices/Audio/HDACodec.cpp
index 8a0cc8b..16ff19e 100644
--- a/src/VBox/Devices/Audio/HDACodec.cpp
+++ b/src/VBox/Devices/Audio/HDACodec.cpp
@@ -3283,81 +3283,6 @@ int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
- do
- {
- /* Initialize the streams to some default values (44.1 kHz, 16-bit signed, 2 channels).
- * The codec's (fixed) delivery rate is 48kHz, so a frame will be delivered every 20.83us. */
- PDMAUDIOSTREAMCFG strmCfg;
- RT_ZERO(strmCfg);
-
- /* Note: Adding the default input/output streams is *not* critical for the overall
- * codec construction result. */
-
- /*
- * Output streams.
- */
- strmCfg.enmDir = PDMAUDIODIR_OUT;
- strmCfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-
- strmCfg.Props.cBits = 16;
- strmCfg.Props.fSigned = true;
- strmCfg.Props.cChannels = 2;
- strmCfg.Props.uHz = 44100;
- strmCfg.Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(strmCfg.Props.cBits, strmCfg.Props.cChannels);
-
- /* Front. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Front");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- int rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_FRONT, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add front output stream: %Rrc\n", rc2));
-
-#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
- /* Center / LFE. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Center / LFE");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
- /** @todo Handle mono channel if only center *or* LFE is available? */
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add center/LFE output stream: %Rrc\n", rc2));
-
- /* Rear. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Rear");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_REAR, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add rear output stream: %Rrc\n", rc2));
-#endif
-
- /*
- * Input streams.
- */
- RT_ZERO(strmCfg);
-
- strmCfg.enmDir = PDMAUDIODIR_IN;
- strmCfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-
- strmCfg.Props.cBits = 16;
- strmCfg.Props.fSigned = true;
- strmCfg.Props.cChannels = 2;
- strmCfg.Props.uHz = 44100;
- strmCfg.Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(strmCfg.Props.cBits, strmCfg.Props.cChannels);
-
-#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Microphone In");
- strmCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add microphone input stream: %Rrc\n", rc2));
-#endif
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Line In");
- strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add line input stream: %Rrc\n", rc2));
-
- } while (0);
-
/*
* Set initial volume.
*/
diff --git a/src/VBox/Devices/Audio/HDAStream.cpp b/src/VBox/Devices/Audio/HDAStream.cpp
index b490360..f61ae51 100644
--- a/src/VBox/Devices/Audio/HDAStream.cpp
+++ b/src/VBox/Devices/Audio/HDAStream.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2017 Oracle Corporation
+ * Copyright (C) 2017-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -52,6 +52,8 @@ int hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis, uint8_t u8SD)
pStream->u8SD = u8SD;
pStream->pMixSink = NULL;
pStream->pHDAState = pThis;
+ pStream->pTimer = pThis->pTimer[u8SD];
+ AssertPtr(pStream->pTimer);
pStream->State.fInReset = false;
pStream->State.fRunning = false;
@@ -59,19 +61,18 @@ int hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis, uint8_t u8SD)
RTListInit(&pStream->State.lstDMAHandlers);
#endif
- int rc = RTCircBufCreate(&pStream->State.pCircBuf, _64K); /** @todo Make this configurable. */
- if (RT_SUCCESS(rc))
- {
- rc = hdaStreamPeriodCreate(&pStream->State.Period);
- if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pStream->State.CritSect);
- }
+ int rc = RTCritSectInit(&pStream->CritSect);
+ AssertRCReturn(rc, rc);
- int rc2;
+ rc = RTCircBufCreate(&pStream->State.pCircBuf, _64K); /** @todo Make this configurable. */
+ AssertRCReturn(rc, rc);
+
+ rc = hdaStreamPeriodCreate(&pStream->State.Period);
+ AssertRCReturn(rc, rc);
#ifdef DEBUG
- rc2 = RTCritSectInit(&pStream->Dbg.CritSect);
- AssertRC(rc2);
+ rc = RTCritSectInit(&pStream->Dbg.CritSect);
+ AssertRCReturn(rc, rc);
#endif
pStream->Dbg.Runtime.fEnabled = pThis->Dbg.fEnabled;
@@ -86,8 +87,8 @@ int hdaStreamCreate(PHDASTREAM pStream, PHDASTATE pThis, uint8_t u8SD)
RTStrPrintf(szFile, sizeof(szFile), "hdaStreamReadSD%RU8", pStream->u8SD);
char szPath[RTPATH_MAX + 1];
- rc2 = DrvAudioHlpGetFileName(szPath, sizeof(szPath), pThis->Dbg.szOutPath, szFile,
- 0 /* uInst */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAG_NONE);
+ int rc2 = DrvAudioHlpGetFileName(szPath, sizeof(szPath), pThis->Dbg.szOutPath, szFile,
+ 0 /* uInst */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAG_NONE);
AssertRC(rc2);
rc2 = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szPath, PDMAUDIOFILE_FLAG_NONE, &pStream->Dbg.Runtime.pFileStream);
AssertRC(rc2);
@@ -132,8 +133,11 @@ void hdaStreamDestroy(PHDASTREAM pStream)
AssertRC(rc2);
#endif
- rc2 = RTCritSectDelete(&pStream->State.CritSect);
- AssertRC(rc2);
+ if (RTCritSectIsInitialized(&pStream->CritSect))
+ {
+ rc2 = RTCritSectDelete(&pStream->CritSect);
+ AssertRC(rc2);
+ }
if (pStream->State.pCircBuf)
{
@@ -144,8 +148,11 @@ void hdaStreamDestroy(PHDASTREAM pStream)
hdaStreamPeriodDestroy(&pStream->State.Period);
#ifdef DEBUG
- rc2 = RTCritSectDelete(&pStream->Dbg.CritSect);
- AssertRC(rc2);
+ if (RTCritSectIsInitialized(&pStream->Dbg.CritSect))
+ {
+ rc2 = RTCritSectDelete(&pStream->Dbg.CritSect);
+ AssertRC(rc2);
+ }
#endif
if (pStream->Dbg.Runtime.fEnabled)
@@ -216,8 +223,19 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
break;
}
+ if ( !pStream->u32CBL
+ || !pStream->u16LVI
+ || !pStream->u64BDLBase
+ || !pStream->u16FIFOS)
+ {
+ return VINF_SUCCESS;
+ }
+
/* Set the stream's frame size. */
pStream->State.cbFrameSize = pCfg->Props.cChannels * (pCfg->Props.cBits / 8 /* To bytes */);
+ LogFunc(("[SD%RU8] cChannels=%RU8, cBits=%RU8 -> cbFrameSize=%RU32\n",
+ pStream->u8SD, pCfg->Props.cChannels, pCfg->Props.cBits, pStream->State.cbFrameSize));
+ Assert(pStream->State.cbFrameSize); /* Frame size must not be 0. */
/*
* Initialize the stream mapping in any case, regardless if
@@ -234,8 +252,11 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS,
pStream->State.Cfg.Props.uHz, rc));
- if ( pStream->u32CBL
- && pStream->u16LVI)
+ /* Make sure that mandatory parameters are set up correctly. */
+ AssertStmt(pStream->u32CBL % pStream->State.cbFrameSize == 0, rc = VERR_INVALID_PARAMETER);
+ AssertStmt(pStream->u16LVI >= 1, rc = VERR_INVALID_PARAMETER);
+
+ if (RT_SUCCESS(rc))
{
/* Make sure that the chosen Hz rate dividable by the stream's rate. */
if (pStream->State.Cfg.Props.uHz % pThis->u16TimerHz != 0)
@@ -262,12 +283,16 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
HDABDLE BDLE;
RT_ZERO(BDLE);
- Assert(pStream->u64BDLBase);
-
int rc2 = hdaBDLEFetch(pThis, &BDLE, pStream->u64BDLBase, 0 /* Entry */);
AssertRC(rc2);
- Assert(BDLE.Desc.u32BufSize % pStream->State.cbFrameSize == 0);
+ /* Note: Do *not* check if this BDLE aligns to the stream's frame size.
+ * It can happen that this isn't the case on some guests, e.g.
+ * on Windows with a 5.1 speaker setup.
+ *
+ * The only thing which counts is that the stream's CBL value
+ * properly aligns to the stream's frame size.
+ */
/* If no custom set position adjustment is set, apply some
* simple heuristics to detect the appropriate position adjustment. */
@@ -339,8 +364,9 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
pStream->State.cbTransferProcessed = 0;
pStream->State.cTransferPendingInterrupts = 0;
+ pStream->State.cbDMALeft = 0;
- const uint64_t cTicksPerHz = TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz;
+ const uint64_t cTicksPerHz = TMTimerGetFreq(pStream->pTimer) / pThis->u16TimerHz;
/* Calculate the timer ticks per byte for this stream. */
pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;
@@ -348,6 +374,7 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
/* Calculate timer ticks per transfer. */
pStream->State.cTransferTicks = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;
+ Assert(pStream->State.cTransferTicks);
/* Initialize the transfer timestamps. */
pStream->State.tsTransferLast = 0;
@@ -366,6 +393,9 @@ int hdaStreamInit(PHDASTREAM pStream, uint8_t uSD)
#endif
}
+ if (RT_FAILURE(rc))
+ LogRel(("HDA: Initializing stream #%RU8 failed with %Rrc\n", pStream->u8SD, rc));
+
return rc;
}
@@ -473,41 +503,35 @@ int hdaStreamEnable(PHDASTREAM pStream, bool fEnable)
int rc = VINF_SUCCESS;
- if (!pStream->pMixSink) /* Stream attached to a sink? */
- {
- AssertMsgFailed(("Stream #%RU8 not has no mixer sink attached\n", pStream->u8SD));
- return VERR_WRONG_ORDER;
- }
-
AUDMIXSINKCMD enmCmd = fEnable
? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
/* First, enable or disable the stream and the stream's sink, if any. */
- if (pStream->pMixSink->pMixSink)
+ if ( pStream->pMixSink
+ && pStream->pMixSink->pMixSink)
rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
if ( RT_SUCCESS(rc)
+ && fEnable
&& pStream->Dbg.Runtime.fEnabled)
{
Assert(DrvAudioHlpPCMPropsAreValid(&pStream->State.Cfg.Props));
if (fEnable)
{
+ if (!DrvAudioHlpFileIsOpen(pStream->Dbg.Runtime.pFileStream))
+ {
int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileStream, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
&pStream->State.Cfg.Props);
AssertRC(rc2);
+ }
- rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileDMA, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
- &pStream->State.Cfg.Props);
- AssertRC(rc2);
- }
- else
- {
- int rc2 = DrvAudioHlpFileClose(pStream->Dbg.Runtime.pFileStream);
- AssertRC(rc2);
-
- rc2 = DrvAudioHlpFileClose(pStream->Dbg.Runtime.pFileDMA);
+ if (!DrvAudioHlpFileIsOpen(pStream->Dbg.Runtime.pFileDMA))
+ {
+ int rc2 = DrvAudioHlpFileOpen(pStream->Dbg.Runtime.pFileDMA, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS,
+ &pStream->State.Cfg.Props);
AssertRC(rc2);
+ }
}
}
@@ -536,8 +560,6 @@ void hdaStreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB)
{
AssertPtrReturnVoid(pStream);
- Assert(u32LPIB % pStream->State.cbFrameSize == 0);
-
Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
pStream->u8SD, u32LPIB, pStream->pHDAState->fDMAPosition));
@@ -601,12 +623,23 @@ bool hdaStreamTransferIsScheduled(PHDASTREAM pStream)
AssertPtrReturn(pStream->pHDAState, false);
+ const uint64_t tsNow = TMTimerGet(pStream->pTimer);
+
const bool fScheduled = pStream->State.fRunning
&& ( pStream->State.cTransferPendingInterrupts
- || pStream->State.tsTransferNext > TMTimerGet(pStream->pHDAState->pTimer));
+ || pStream->State.tsTransferNext > tsNow);
- Log3Func(("[SD%RU8] tsTransferNext=%RU64, cTransferPendingInterrupts=%RU8 -> %RTbool\n",
- pStream->u8SD, pStream->State.tsTransferNext, pStream->State.cTransferPendingInterrupts, fScheduled));
+#ifdef LOG_ENABLED
+ if (fScheduled)
+ {
+ if (pStream->State.cTransferPendingInterrupts)
+ Log3Func(("[SD%RU8] Scheduled (%RU8 IRQs pending)\n",
+ pStream->u8SD, pStream->State.cTransferPendingInterrupts));
+ else
+ Log3Func(("[SD%RU8] Scheduled in %RU64\n",
+ pStream->u8SD, pStream->State.tsTransferNext - tsNow));
+ }
+#endif
return fScheduled;
}
@@ -683,6 +716,8 @@ int hdaStreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32
cbWrittenTotal += (uint32_t)cbDst;
}
+ Log3Func(("cbWrittenTotal=%RU32\n", cbWrittenTotal));
+
if (pcbWritten)
*pcbWritten = cbWrittenTotal;
@@ -807,7 +842,7 @@ int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
return VINF_SUCCESS;
}
- const uint64_t tsNow = TMTimerGet(pThis->pTimer);
+ const uint64_t tsNow = TMTimerGet(pStream->pTimer);
if (!pStream->State.tsTransferLast)
pStream->State.tsTransferLast = tsNow;
@@ -936,45 +971,76 @@ int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
rc = hdaDMARead(pThis, pStream, abChunk, cbChunk, &cbDMA /* pcbRead */);
if (RT_SUCCESS(rc))
{
- uint32_t cbDMAWritten = 0;
- uint32_t cbDMALeft = cbDMA;
-
- if (cbDMALeft > RTCircBufFree(pCircBuf))
+#ifndef VBOX_WITH_HDA_AUDIO_INTERLEAVING_STREAMS_SUPPORT
+ /*
+ * Most guests don't use different stream frame sizes than
+ * the default one, so save a bit of CPU time and don't go into
+ * the frame extraction code below.
+ *
+ * Only macOS guests need the frame extraction branch below at the moment AFAIK.
+ */
+ if (pStream->State.cbFrameSize == HDA_FRAME_SIZE)
{
- LogRel2(("HDA: FIFO overflow for stream #%RU8 (%RU32 bytes outstanding)\n",
- pStream->u8SD, cbDMALeft - RTCircBufFree(pCircBuf)));
+ uint32_t cbDMARead = 0;
+ uint32_t cbDMALeft = RT_MIN(cbDMA, (uint32_t)RTCircBufFree(pCircBuf));
- /* Try to read as much as possible. */
- cbDMALeft = (uint32_t)RTCircBufFree(pCircBuf);
+ while (cbDMALeft)
+ {
+ void *pvBuf; size_t cbBuf;
+ RTCircBufAcquireWriteBlock(pCircBuf, cbDMALeft, &pvBuf, &cbBuf);
- rc = VERR_BUFFER_OVERFLOW;
- }
+ if (cbBuf)
+ {
+ memcpy(pvBuf, abChunk + cbDMARead, cbBuf);
+ cbDMARead += (uint32_t)cbBuf;
+ cbDMALeft -= (uint32_t)cbBuf;
+ }
-#ifndef VBOX_WITH_HDA_AUDIO_INTERLEAVING_STREAMS_SUPPORT
- /**
- * The following code extracts the required audio stream (channel) data
- * of non-interleaved *and* interleaved audio streams.
- *
- * We by default only support 2 channels with 16-bit samples (HDA_FRAME_SIZE),
- * but an HDA audio stream can have interleaved audio data of multiple audio
- * channels in such a single stream ("AA,AA,AA vs. AA,BB,AA,BB").
- *
- * So take this into account by just handling the first channel in such a stream ("A")
- * and just discard the other channel's data.
- */
- while (cbDMALeft)
+ RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
+ }
+ }
+ else
{
- void *pvBuf; size_t cbBuf;
- RTCircBufAcquireWriteBlock(pCircBuf, HDA_FRAME_SIZE, &pvBuf, &cbBuf);
+ /**
+ * The following code extracts the required audio stream (channel) data
+ * of non-interleaved *and* interleaved audio streams.
+ *
+ * We by default only support 2 channels with 16-bit samples (HDA_FRAME_SIZE),
+ * but an HDA audio stream can have interleaved audio data of multiple audio
+ * channels in such a single stream ("AA,AA,AA vs. AA,BB,AA,BB").
+ *
+ * So take this into account by just handling the first channel in such a stream ("A")
+ * and just discard the other channel's data.
+ *
+ * @todo Optimize this stuff -- copying only one frame a time is expensive.
+ */
+ uint32_t cbDMARead = pStream->State.cbDMALeft ? pStream->State.cbFrameSize - pStream->State.cbDMALeft : 0;
+ uint32_t cbDMALeft = RT_MIN(cbDMA, (uint32_t)RTCircBufFree(pCircBuf));
+
+ while (cbDMALeft >= pStream->State.cbFrameSize)
+ {
+ void *pvBuf; size_t cbBuf;
+ RTCircBufAcquireWriteBlock(pCircBuf, HDA_FRAME_SIZE, &pvBuf, &cbBuf);
- if (cbBuf)
- memcpy(pvBuf, abChunk + cbDMAWritten, cbBuf);
+ AssertBreak(cbDMARead <= sizeof(abChunk));
- RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
+ if (cbBuf)
+ memcpy(pvBuf, abChunk + cbDMARead, cbBuf);
- cbDMALeft -= (uint32_t)pStream->State.cbFrameSize;
- cbDMAWritten += (uint32_t)pStream->State.cbFrameSize;
+ RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
+
+ Assert(cbDMALeft >= pStream->State.cbFrameSize);
+ cbDMALeft -= pStream->State.cbFrameSize;
+ cbDMARead += pStream->State.cbFrameSize;
+ }
+
+ pStream->State.cbDMALeft = cbDMALeft;
+ Assert(pStream->State.cbDMALeft < pStream->State.cbFrameSize);
}
+
+ const size_t cbFree = RTCircBufFree(pCircBuf);
+ if (!cbFree)
+ LogRel2(("HDA: FIFO of stream #%RU8 full, discarding audio data\n", pStream->u8SD));
#else
/** @todo This needs making use of HDAStreamMap + HDAStreamChannel. */
# error "Implement reading interleaving streams support here."
@@ -991,8 +1057,6 @@ int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
if (cbDMA)
{
- Assert(cbDMA % pStream->State.cbFrameSize == 0);
-
/* We always increment the position of DMA buffer counter because we're always reading
* into an intermediate buffer. */
pBDLE->State.u32BufOff += (uint32_t)cbDMA;
@@ -1068,7 +1132,6 @@ int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
pStream->u8SD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));
/* Sanity. */
- Assert(cbProcessed % pStream->State.cbFrameSize == 0);
Assert(cbProcessed == cbToProcess);
Assert(cbLeft == 0);
@@ -1166,11 +1229,12 @@ int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
{
Log3Func(("[SD%RU8] Scheduling timer\n", pStream->u8SD));
- TMTimerUnlock(pThis->pTimer);
+ TMTimerUnlock(pStream->pTimer);
- hdaTimerSet(pThis, tsTransferNext, false /* fForce */);
+ LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
+ hdaTimerSet(pStream->pHDAState, pStream, tsTransferNext, false /* fForce */);
- TMTimerLock(pThis->pTimer, VINF_SUCCESS);
+ TMTimerLock(pStream->pTimer, VINF_SUCCESS);
pStream->State.tsTransferNext = tsTransferNext;
}
@@ -1271,7 +1335,7 @@ void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
else /* Input (SDI). */
{
#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
- if (fInTimer)
+ if (!fInTimer)
{
#endif
rc2 = AudioMixerSinkUpdate(pSink);
@@ -1335,6 +1399,23 @@ void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
}
}
#endif
+#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
+ }
+ else /* fInTimer */
+ {
+#endif
+ const uint64_t tsNow = RTTimeMilliTS();
+ static uint64_t s_lasti = 0;
+ if (s_lasti == 0)
+ s_lasti = tsNow;
+
+ if (tsNow - s_lasti >= 10) /** @todo Fix this properly. */
+ {
+ rc2 = hdaStreamAsyncIONotify(pStream);
+ AssertRC(rc2);
+
+ s_lasti = tsNow;
+ }
const uint32_t cbToTransfer = hdaStreamGetUsed(pStream);
if (cbToTransfer)
@@ -1343,7 +1424,7 @@ void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
AssertRC(rc2);
}
#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
- } /* fInTimer */
+ }
#endif
}
}
@@ -1357,7 +1438,7 @@ void hdaStreamUpdate(PHDASTREAM pStream, bool fInTimer)
void hdaStreamLock(PHDASTREAM pStream)
{
AssertPtrReturnVoid(pStream);
- int rc2 = RTCritSectEnter(&pStream->State.CritSect);
+ int rc2 = RTCritSectEnter(&pStream->CritSect);
AssertRC(rc2);
}
@@ -1370,7 +1451,7 @@ void hdaStreamLock(PHDASTREAM pStream)
void hdaStreamUnlock(PHDASTREAM pStream)
{
AssertPtrReturnVoid(pStream);
- int rc2 = RTCritSectLeave(&pStream->State.CritSect);
+ int rc2 = RTCritSectLeave(&pStream->CritSect);
AssertRC(rc2);
}
diff --git a/src/VBox/Devices/Audio/HDAStream.h b/src/VBox/Devices/Audio/HDAStream.h
index 76a19d6..d049ce3 100644
--- a/src/VBox/Devices/Audio/HDAStream.h
+++ b/src/VBox/Devices/Audio/HDAStream.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2017 Oracle Corporation
+ * Copyright (C) 2017-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -121,8 +121,6 @@ typedef struct HDASTREAMSTATE
volatile bool fRunning;
/** Unused, padding. */
uint8_t Padding0[3];
- /** Critical section to serialize access. */
- RTCRITSECT CritSect;
#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
/** Asynchronous I/O state members. */
HDASTREAMSTATEAIO AIO;
@@ -170,8 +168,13 @@ typedef struct HDASTREAMSTATE
/** List of DMA handlers. */
RTLISTANCHORR3 lstDMAHandlers;
#endif
+ /** How much DMA data from a previous transfer is left to be processed (in bytes).
+ * This can happen if the stream's frame size is bigger (e.g. 16 bytes) than
+ * the current DMA FIFO can hold (e.g. 10 bytes). Mostly needed for more complex
+ * stuff like interleaved surround streams. */
+ uint16_t cbDMALeft;
/** Unused, padding. */
- uint8_t Padding3[3];
+ uint8_t Padding3;
} HDASTREAMSTATE, *PHDASTREAMSTATE;
/**
@@ -216,6 +219,10 @@ typedef struct HDASTREAM
R3PTRTYPE(PHDASTATE) pHDAState;
/** Pointer to HDA sink this stream is attached to. */
R3PTRTYPE(PHDAMIXERSINK) pMixSink;
+ /** The stream'S critical section to serialize access. */
+ RTCRITSECT CritSect;
+ /** Pointer to the stream's timer. */
+ PTMTIMERR3 pTimer;
/** Internal state of this stream. */
HDASTREAMSTATE State;
/** Debug information. */
@@ -261,6 +268,13 @@ void hdaStreamUnregisterDMAHandlers(PHDASTREAM pStream);
# endif /* HDA_USE_DMA_ACCESS_HANDLER */
/** @} */
+/** @name Timer functions.
+ * @{
+ */
+DECLCALLBACK(void) hdaStreamTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
+/** @} */
+
+
/** @name Async I/O stream functions.
* @{
*/
@@ -276,6 +290,5 @@ void hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable);
/** @} */
#endif /* IN_RING3 */
-
#endif /* !HDA_STREAM_H */
diff --git a/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp b/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
index f5c4a2a..dc2b8b7 100644
--- a/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
+++ b/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2017 Oracle Corporation
+ * Copyright (C) 2014-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -135,8 +135,9 @@ static int tstSingle(RTTEST hTest)
uint32_t cToRead = AudioMixBufSize(&mb) - cFramesWrittenAbs - 1;
for (uint32_t i = 0; i < cToRead; i++)
{
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
+ RTTESTI_CHECK_RC_OK(AudioMixBufAcquireReadBlock(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
RTTESTI_CHECK(cFramesRead == 1);
+ AudioMixBufReleaseReadBlock(&mb, cFramesRead);
AudioMixBufFinish(&mb, cFramesRead);
}
RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
@@ -144,8 +145,9 @@ static int tstSingle(RTTEST hTest)
RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, cBufSize - cFramesWrittenAbs - 1));
RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize - cToRead);
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
+ RTTESTI_CHECK_RC_OK(AudioMixBufAcquireReadBlock(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
RTTESTI_CHECK(cFramesRead == 1);
+ AudioMixBufReleaseReadBlock(&mb, cFramesRead);
AudioMixBufFinish(&mb, cFramesRead);
RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - cFramesWrittenAbs);
RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, cBufSize - cFramesWrittenAbs));
@@ -278,10 +280,11 @@ static int tstParentChild(RTTEST hTest)
uint32_t cParentSamples = AudioMixBufUsed(&parent);
while (cParentSamples)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, pvBuf, cbBuf, &cFramesRead));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, pvBuf, cbBuf, &cFramesRead));
if (!cFramesRead)
break;
+ AudioMixBufReleaseReadBlock(&parent, cFramesRead);
AudioMixBufFinish(&parent, cFramesRead);
RTTESTI_CHECK(cParentSamples >= cFramesRead);
@@ -378,10 +381,11 @@ static int tstConversion8(RTTEST hTest)
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cFramesRead));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
if (!cFramesRead)
break;
cFramesTotalRead += cFramesRead;
+ AudioMixBufReleaseReadBlock(&parent, cFramesRead);
AudioMixBufFinish(&parent, cFramesRead);
}
@@ -476,10 +480,11 @@ static int tstConversion16(RTTEST hTest)
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cFramesRead));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
if (!cFramesRead)
break;
cFramesTotalRead += cFramesRead;
+ AudioMixBufReleaseReadBlock(&parent, cFramesRead);
AudioMixBufFinish(&parent, cFramesRead);
}
RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
@@ -566,10 +571,11 @@ static int tstVolume(RTTEST hTest)
cFramesTotalRead = 0;
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cFramesRead));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
if (!cFramesRead)
break;
cFramesTotalRead += cFramesRead;
+ AudioMixBufReleaseReadBlock(&parent, cFramesRead);
AudioMixBufFinish(&parent, cFramesRead);
}
RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
@@ -597,10 +603,11 @@ static int tstVolume(RTTEST hTest)
cFramesTotalRead = 0;
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cFramesRead));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
if (!cFramesRead)
break;
cFramesTotalRead += cFramesRead;
+ AudioMixBufReleaseReadBlock(&parent, cFramesRead);
AudioMixBufFinish(&parent, cFramesRead);
}
RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
index d69b550..d3cf53a 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
@@ -7395,7 +7395,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x3726 class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2e
- db 'Oracle VM VirtualBox Version 5.2.6 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.2.8 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462e 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
@@ -8292,7 +8292,7 @@ _vbebios_vendor_name: ; 0xc7c7b LB 0x13
_vbebios_product_name: ; 0xc7c8e LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7caf LB 0x23
- db 'Oracle VM VirtualBox Version 5.2.6', 000h
+ db 'Oracle VM VirtualBox Version 5.2.8', 000h
_vbebios_info_string: ; 0xc7cd2 LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cfd LB 0x29
@@ -8348,4 +8348,4 @@ section CONST2 progbits vstart=0x7d26 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, 0f4h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0f0h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
index 4fb8f10..50a172e 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
@@ -1 +1 @@
-61e8dfab18a45ee8cad8ed3f36a9d589 *VBoxVgaBios286.rom
+9bedb877a5c7bfdc2fba631c25867da2 *VBoxVgaBios286.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
index 76e6c86..d7c7ba6 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
@@ -6867,7 +6867,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x3726 class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2e
- db 'Oracle VM VirtualBox Version 5.2.6 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.2.8 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462e 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
@@ -7764,7 +7764,7 @@ _vbebios_vendor_name: ; 0xc7c7b LB 0x13
_vbebios_product_name: ; 0xc7c8e LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7caf LB 0x23
- db 'Oracle VM VirtualBox Version 5.2.6', 000h
+ db 'Oracle VM VirtualBox Version 5.2.8', 000h
_vbebios_info_string: ; 0xc7cd2 LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cfd LB 0x29
@@ -7820,4 +7820,4 @@ section CONST2 progbits vstart=0x7d26 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, 069h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 065h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
index bd79cd9..018ab16 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
@@ -1 +1 @@
-924ad92970806a9f9de054559d0f84e3 *VBoxVgaBios386.rom
+bbadc92158d4bd6550902afd1d45ee5b *VBoxVgaBios386.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
index c4fe355..00e2c1c 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
@@ -7514,7 +7514,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x3726 class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2e
- db 'Oracle VM VirtualBox Version 5.2.6 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.2.8 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462e 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
@@ -8411,7 +8411,7 @@ _vbebios_vendor_name: ; 0xc7c7b LB 0x13
_vbebios_product_name: ; 0xc7c8e LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7caf LB 0x23
- db 'Oracle VM VirtualBox Version 5.2.6', 000h
+ db 'Oracle VM VirtualBox Version 5.2.8', 000h
_vbebios_info_string: ; 0xc7cd2 LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cfd LB 0x29
@@ -8467,4 +8467,4 @@ section CONST2 progbits vstart=0x7d26 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, 058h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 054h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
index 75a7662..43b573e 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
@@ -1 +1 @@
-d73c0230d0134906efe4364eb031e0d2 *VBoxVgaBios8086.rom
+16b1401e4cf63f53b13082586975d4f4 *VBoxVgaBios8086.rom
diff --git a/src/VBox/Devices/Network/DevE1000.cpp b/src/VBox/Devices/Network/DevE1000.cpp
index 3b77d35..533ac47 100644
--- a/src/VBox/Devices/Network/DevE1000.cpp
+++ b/src/VBox/Devices/Network/DevE1000.cpp
@@ -2715,7 +2715,16 @@ static int e1kRegWriteCTRL(PE1KSTATE pThis, uint32_t offset, uint32_t index, uin
/* It should take about 2 seconds for the link to come up */
e1kArmTimer(pThis, pThis->CTX_SUFF(pLUTimer), E1K_INIT_LINKUP_DELAY_US);
}
-#endif /* E1K_LSC_ON_SLU */
+#else /* !E1K_LSC_ON_SLU */
+ if ( (value & CTRL_SLU)
+ && !(CTRL & CTRL_SLU)
+ && pThis->fCableConnected
+ && !TMTimerIsActive(pThis->CTX_SUFF(pLUTimer)))
+ {
+ /* PXE does not use LSC interrupts, see @bugref{9113}. */
+ STATUS |= STATUS_LU;
+ }
+#endif /* !E1K_LSC_ON_SLU */
if ((value & CTRL_VME) != (CTRL & CTRL_VME))
{
E1kLog(("%s VLAN Mode %s\n", pThis->szPrf, (value & CTRL_VME) ? "Enabled" : "Disabled"));
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
index be92738..cd12bc3 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
@@ -1172,7 +1172,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0d8e LB 0x12
- db 'VirtualBox 5.2.6', 000h, 000h
+ db 'VirtualBox 5.2.8', 000h, 000h
_bios_prefix_string: ; 0xf0da0 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0da8 LB 0x6
@@ -17873,4 +17873,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
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, 0ddh
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 0dbh
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
index 6d8ae4d..84a1f8a 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
@@ -1 +1 @@
-6f42b2c17eb6b184081991fbfb780cca *VBoxPcBios286.rom
+328c27a6711e56587d8b69e67baaf43e *VBoxPcBios286.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
index 95b0be5..845ec24 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
@@ -1136,7 +1136,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcf0 class=DATA group=DGROUP
section CONST2 progbits vstart=0xda0 align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0da0 LB 0x12
- db 'VirtualBox 5.2.6', 000h, 000h
+ db 'VirtualBox 5.2.8', 000h, 000h
_bios_prefix_string: ; 0xf0db2 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0dba LB 0x6
@@ -17367,4 +17367,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
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, 008h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 006h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
index 49fdca3..a1d6f33 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
@@ -1 +1 @@
-d624fd8162ff1a3e893807aecb4e8ba7 *VBoxPcBios386.rom
+7dd62f49386d02d6a637cf08f08e5405 *VBoxPcBios386.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
index ad5b8cb..281614e 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
@@ -1172,7 +1172,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0d8e LB 0x12
- db 'VirtualBox 5.2.6', 000h, 000h
+ db 'VirtualBox 5.2.8', 000h, 000h
_bios_prefix_string: ; 0xf0da0 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0da8 LB 0x6
@@ -18294,4 +18294,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
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, 0fbh, 036h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fbh, 034h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
index 9c298f1..1e4415a 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
@@ -1 +1 @@
-a2a6934aac6689d28da376126c8eaa01 *VBoxPcBios8086.rom
+2ad601e4e51facc25cc1fcb5566b2a20 *VBoxPcBios8086.rom
diff --git a/src/VBox/Devices/PC/DevPcArch.cpp b/src/VBox/Devices/PC/DevPcArch.cpp
index a024da7..544d844 100644
--- a/src/VBox/Devices/PC/DevPcArch.cpp
+++ b/src/VBox/Devices/PC/DevPcArch.cpp
@@ -22,6 +22,7 @@
#define LOG_GROUP LOG_GROUP_DEV_PC_ARCH
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/mm.h>
+#include <VBox/vmm/pgm.h>
#include <VBox/log.h>
#include <VBox/err.h>
#include <iprt/assert.h>
@@ -185,6 +186,67 @@ pcarchIOPortPS2SysControlPortAWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT P
/**
+ * @callback_method_impl{FNIOMMMIOWRITE, Ignores writes to the reserved memory.}
+ */
+static DECLCALLBACK(int) pcarchReservedMemoryWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr,
+ void const *pv, unsigned cb)
+{
+ Log2(("pcarchReservedMemoryRead: %#RGp LB %#x %.*Rhxs\n", GCPhysAddr, cb, RT_MIN(cb, 16), pv));
+ NOREF(pDevIns); NOREF(pvUser); NOREF(GCPhysAddr); NOREF(pv); NOREF(cb);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMMMIOREAD, The reserved memory reads as 0xff.}
+ */
+static DECLCALLBACK(int) pcarchReservedMemoryRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
+{
+ Log2(("pcarchReservedMemoryRead: %#RGp LB %#x\n", GCPhysAddr, cb));
+ NOREF(pDevIns); NOREF(pvUser); NOREF(GCPhysAddr);
+ memset(pv, 0xff, cb);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnInitComplete,
+ * Turn RAM pages between 0xa0000 and 0xeffff into reserved memory.}
+ * NB: At least some OS X versions (El Capitan, Sierra) get upset and panic
+ * early in the boot when we make memory between 0x0f0000-0x100000 reserved
+ * and non-writable.
+ */
+static DECLCALLBACK(int) pcarchInitComplete(PPDMDEVINS pDevIns)
+{
+ PVM pVM = PDMDevHlpGetVM(pDevIns);
+ int iRegion = 0;
+ RTGCPHYS const GCPhysEnd = 0x0f0000;
+ RTGCPHYS GCPhysCur = 0x0a0000;
+ do
+ {
+ if (!PGMPhysIsGCPhysNormal(pVM, GCPhysCur))
+ GCPhysCur += X86_PAGE_SIZE;
+ else
+ {
+ RTGCPHYS const GCPhysStart = GCPhysCur;
+ do
+ GCPhysCur += X86_PAGE_SIZE;
+ while (GCPhysCur < GCPhysEnd && PGMPhysIsGCPhysNormal(pVM, GCPhysCur));
+
+ int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysStart, GCPhysCur - GCPhysStart, NULL /*pvUser*/,
+ IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
+ pcarchReservedMemoryWrite, pcarchReservedMemoryRead,
+ MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS /* bad bird*/, "PC Arch Reserved #%u", iRegion));
+ AssertLogRelRCReturn(rc, rc);
+ iRegion++;
+ }
+ } while (GCPhysCur < GCPhysEnd);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
static DECLCALLBACK(int) pcarchConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
@@ -270,7 +332,7 @@ const PDMDEVREG g_DevicePcArch =
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete. */
- NULL,
+ pcarchInitComplete,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
diff --git a/src/VBox/Devices/Serial/DevSerial.cpp b/src/VBox/Devices/Serial/DevSerial.cpp
index 185a805..04e418d 100644
--- a/src/VBox/Devices/Serial/DevSerial.cpp
+++ b/src/VBox/Devices/Serial/DevSerial.cpp
@@ -1114,7 +1114,7 @@ static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
pThis->rbr = 0;
pThis->ier = 0;
pThis->iir = UART_IIR_NO_INT;
- pThis->lcr = 0;
+ pThis->lcr = 3; /* 8 data bits, no parity, 1 stop bit */
pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
/* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
@@ -1126,6 +1126,9 @@ static DECLCALLBACK(void) serialReset(PPDMDEVINS pDevIns)
pThis->char_transmit_time = (tf / 9600) * 10;
serial_tsr_retry_update_parameters(pThis, tf);
+ /* Update parameters of the underlying driver to stay in sync. */
+ serial_update_parameters(pThis);
+
fifo_clear(pThis, RECV_FIFO);
fifo_clear(pThis, XMIT_FIFO);
@@ -1309,8 +1312,6 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->transmit_timerR0 = TMTimerR0Ptr(pThis->transmit_timerR3);
pThis->transmit_timerRC = TMTimerRCPtr(pThis->transmit_timerR3);
- serialReset(pDevIns);
-
#ifdef VBOX_SERIAL_PCI
/*
* Register the PCI Device and region.
@@ -1386,6 +1387,7 @@ static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
return rc;
}
+ serialReset(pDevIns);
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/Storage/DevAHCI.cpp b/src/VBox/Devices/Storage/DevAHCI.cpp
index be92fb0..722c3fb 100644
--- a/src/VBox/Devices/Storage/DevAHCI.cpp
+++ b/src/VBox/Devices/Storage/DevAHCI.cpp
@@ -127,6 +127,9 @@
#define AHCI_SERIAL_NUMBER_LENGTH 20
#define AHCI_FIRMWARE_REVISION_LENGTH 8
#define AHCI_MODEL_NUMBER_LENGTH 40
+#define AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH 8
+#define AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH 16
+#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH 4
/** ATAPI sense info size. */
#define ATAPI_SENSE_SIZE 64
@@ -412,9 +415,7 @@ typedef struct AHCIPort
/** The status LED state for this drive. */
PDMLED Led;
-#if HC_ARCH_BITS == 64
uint32_t u32Alignment3;
-#endif
/** Async IO Thread. */
R3PTRTYPE(PPDMTHREAD) pAsyncIOThread;
@@ -430,6 +431,12 @@ typedef struct AHCIPort
char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
/** The model number to use for IDENTIFY DEVICE commands. */
char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
+ /** The vendor identification string for SCSI INQUIRY commands. */
+ char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
+ /** The product identification string for SCSI INQUIRY commands. */
+ char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
+ /** The revision string for SCSI INQUIRY commands. */
+ char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
/** Error counter */
uint32_t cErrors;
@@ -2617,6 +2624,23 @@ static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIMEDIAPORT pInterface
return VINF_SUCCESS;
}
+/**
+ * @interface_method_impl{PDMIMEDIAPORT,pfnQueryScsiInqStrings}
+ */
+static DECLCALLBACK(int) ahciR3PortQueryScsiInqStrings(PPDMIMEDIAPORT pInterface, const char **ppszVendorId,
+ const char **ppszProductId, const char **ppszRevision)
+{
+ PAHCIPort pAhciPort = PDMIMEDIAPORT_2_PAHCIPORT(pInterface);
+
+ if (ppszVendorId)
+ *ppszVendorId = &pAhciPort->szInquiryVendorId[0];
+ if (ppszProductId)
+ *ppszProductId = &pAhciPort->szInquiryProductId[0];
+ if (ppszRevision)
+ *ppszRevision = &pAhciPort->szInquiryRevision[0];
+ return VINF_SUCCESS;
+}
+
#ifdef LOG_ENABLED
/**
@@ -5509,6 +5533,43 @@ static int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *ps
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
+ /* There are three other identification strings for CD drives used for INQUIRY */
+ if (pAhciPort->fATAPI)
+ {
+ rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
+ "VBOX");
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
+ return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
+ N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
+ }
+
+ rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
+ "CD-ROM");
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
+ return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
+ N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
+ }
+
+ rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
+ "1.0");
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
+ return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
+ N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
+ }
+ }
+
return rc;
}
@@ -6051,6 +6112,7 @@ static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
pAhciPort->IMediaExPort.pfnIoReqStateChanged = ahciR3IoReqStateChanged;
pAhciPort->IMediaExPort.pfnMediumEjected = ahciR3MediumEjected;
pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
+ pAhciPort->IPort.pfnQueryScsiInqStrings = ahciR3PortQueryScsiInqStrings;
pAhciPort->fWrkThreadSleeping = true;
/* Query per port configuration options if available. */
diff --git a/src/VBox/Devices/Storage/DevATA.cpp b/src/VBox/Devices/Storage/DevATA.cpp
index a864f0a..be8270a 100644
--- a/src/VBox/Devices/Storage/DevATA.cpp
+++ b/src/VBox/Devices/Storage/DevATA.cpp
@@ -342,9 +342,9 @@ typedef struct ATADevState
PDMIMOUNTNOTIFY IMountNotify;
/** The LUN #. */
RTUINT iLUN;
-#if HC_ARCH_BITS == 64
+
RTUINT Alignment2; /**< Align pDevInsR3 correctly. */
-#endif
+
/** Pointer to device instance. */
PPDMDEVINSR3 pDevInsR3;
/** Pointer to controller instance. */
diff --git a/src/VBox/Devices/Storage/DrvHostDVD.cpp b/src/VBox/Devices/Storage/DrvHostDVD.cpp
index 21b543b..3feead0 100644
--- a/src/VBox/Devices/Storage/DrvHostDVD.cpp
+++ b/src/VBox/Devices/Storage/DrvHostDVD.cpp
@@ -52,6 +52,8 @@ typedef struct DRVHOSTDVD
PTRACKLIST pTrackList;
/** ATAPI sense data. */
uint8_t abATAPISense[ATAPI_SENSE_SIZE];
+ /** Flag whether to overwrite the inquiry data with our emulated settings. */
+ bool fInquiryOverwrite;
} DRVHOSTDVD;
/** Pointer to the host DVD driver instance data. */
typedef DRVHOSTDVD *PDRVHOSTDVD;
@@ -346,17 +348,28 @@ static DECLCALLBACK(int) drvHostDvdIoReqSendScsiCmd(PPDMIMEDIAEX pInterface, PDM
{
Assert(cbXferCur <= cbXfer);
- if (pbCdb[0] == SCSI_INQUIRY)
+ if ( pbCdb[0] == SCSI_INQUIRY
+ && pThis->fInquiryOverwrite)
{
+ const char *pszInqVendorId = "VBOX";
+ const char *pszInqProductId = "CD-ROM";
+ const char *pszInqRevision = "1.0";
+
+ if (pThis->Core.pDrvMediaPort->pfnQueryScsiInqStrings)
+ {
+ rc = pThis->Core.pDrvMediaPort->pfnQueryScsiInqStrings(pThis->Core.pDrvMediaPort, &pszInqVendorId,
+ &pszInqProductId, &pszInqRevision);
+ AssertRC(rc);
+ }
/* Make sure that the real drive cannot be identified.
* Motivation: changing the VM configuration should be as
* invisible as possible to the guest. */
if (cbXferCur >= 8 + 8)
- scsiPadStr((uint8_t *)pvBuf + 8, "VBOX", 8);
+ scsiPadStr((uint8_t *)pvBuf + 8, pszInqVendorId, 8);
if (cbXferCur >= 16 + 16)
- scsiPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
+ scsiPadStr((uint8_t *)pvBuf + 16, pszInqProductId, 16);
if (cbXferCur >= 32 + 4)
- scsiPadStr((uint8_t *)pvBuf + 32, "1.0", 4);
+ scsiPadStr((uint8_t *)pvBuf + 32, pszInqRevision, 4);
}
if (cbXferCur)
@@ -432,8 +445,13 @@ static DECLCALLBACK(int) drvHostDvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg,
PDRVHOSTDVD pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDVD);
LogFlow(("drvHostDvdConstruct: iInstance=%d\n", pDrvIns->iInstance));
+ int rc = CFGMR3QueryBoolDef(pCfg, "InquiryOverwrite", &pThis->fInquiryOverwrite, true);
+ if (RT_FAILURE(rc))
+ return PDMDRV_SET_ERROR(pDrvIns, rc,
+ N_("HostDVD configuration error: failed to read \"InquiryOverwrite\" as boolean"));
+
bool fPassthrough;
- int rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
+ rc = CFGMR3QueryBool(pCfg, "Passthrough", &fPassthrough);
if (RT_SUCCESS(rc) && fPassthrough)
{
pThis->Core.IMedia.pfnSendCmd = drvHostDvdSendCmd;
@@ -447,7 +465,7 @@ static DECLCALLBACK(int) drvHostDvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg,
/*
* Init instance data.
*/
- rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0",
+ rc = DRVHostBaseInit(pDrvIns, pCfg, "Path\0Interval\0Locked\0BIOSVisible\0AttachFailError\0Passthrough\0InquiryOverwrite\0",
PDMMEDIATYPE_DVD);
LogFlow(("drvHostDvdConstruct: returns %Rrc\n", rc));
return rc;
diff --git a/src/VBox/Devices/Storage/DrvSCSI.cpp b/src/VBox/Devices/Storage/DrvSCSI.cpp
index b10ba75..f7262ab 100644
--- a/src/VBox/Devices/Storage/DrvSCSI.cpp
+++ b/src/VBox/Devices/Storage/DrvSCSI.cpp
@@ -443,6 +443,21 @@ static DECLCALLBACK(int) drvscsiGetFeatureFlags(VSCSILUN hVScsiLun, void *pvScsi
return VINF_SUCCESS;
}
+/**
+ * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunQueryInqStrings}
+ */
+static DECLCALLBACK(int) drvscsiQueryInqStrings(VSCSILUN hVScsiLun, void *pvScsiLunUser, const char **ppszVendorId,
+ const char **ppszProductId, const char **ppszProductLevel)
+{
+ RT_NOREF(hVScsiLun);
+ PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
+
+ if (pThis->pDevMediaPort->pfnQueryScsiInqStrings)
+ return pThis->pDevMediaPort->pfnQueryScsiInqStrings(pThis->pDevMediaPort, ppszVendorId,
+ ppszProductId, ppszProductLevel);
+
+ return VERR_NOT_FOUND;
+}
/* -=-=-=-=- IPortEx -=-=-=-=- */
@@ -1415,6 +1430,7 @@ static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, ui
pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue;
pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags;
pThis->VScsiIoCallbacks.pfnVScsiLunMediumSetLock = drvscsiSetLock;
+ pThis->VScsiIoCallbacks.pfnVScsiLunQueryInqStrings = drvscsiQueryInqStrings;
rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiIoReqVScsiReqCompleted, pThis);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n", rc), rc);
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h b/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
index 74ef3d7..d3e69d5 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
@@ -628,7 +628,7 @@ DECLINLINE(int) vscsiLunReqTransferEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIIOREQIN
*
* @returns VBox status code.
* @param pVScsiLun The LUN.
- * @param pVScsiIoReq The I/O request to enqueue.
+ * @param pfFeatures Where to sthre supported flags on success.
*/
DECLINLINE(int) vscsiLunGetFeatureFlags(PVSCSILUNINT pVScsiLun, uint64_t *pfFeatures)
{
@@ -638,6 +638,29 @@ DECLINLINE(int) vscsiLunGetFeatureFlags(PVSCSILUNINT pVScsiLun, uint64_t *pfFeat
}
/**
+ * Wrapper for the query INQUIRY strings I/O callback.
+ *
+ * @returns VBox status code.
+ * @param pVScsiLun The LUN.
+ * @param ppszVendorId Where to store the pointer to the vendor ID string to report.
+ * @param ppszProductId Where to store the pointer to the product ID string to report.
+ * @param ppszProductLevel Where to store the pointer to the revision string to report.
+ */
+DECLINLINE(int) vscsiLunQueryInqStrings(PVSCSILUNINT pVScsiLun, const char **ppszVendorId,
+ const char **ppszProductId, const char **ppszProductLevel)
+{
+ if (pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunQueryInqStrings)
+ {
+ return pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunQueryInqStrings(pVScsiLun,
+ pVScsiLun->pvVScsiLunUser,
+ ppszVendorId, ppszProductId,
+ ppszProductLevel);
+ }
+
+ return VERR_NOT_FOUND;
+}
+
+/**
* Wrapper around vscsiReqSenseOkSet()
*/
DECLINLINE(int) vscsiLunReqSenseOkSet(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
index cf223de..ffe3d4a 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
@@ -1102,9 +1102,16 @@ static DECLCALLBACK(int) vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQ
ScsiInquiryReply.u3AnsiVersion = 0x05; /* MMC-?? compliant */
ScsiInquiryReply.fCmdQue = 1; /* Command queuing supported. */
ScsiInquiryReply.fWBus16 = 1;
- scsiPadStrS(ScsiInquiryReply.achVendorId, "VBOX", 8);
- scsiPadStrS(ScsiInquiryReply.achProductId, "CD-ROM", 16);
- scsiPadStrS(ScsiInquiryReply.achProductLevel, "1.0", 4);
+
+ const char *pszVendorId = "VBOX";
+ const char *pszProductId = "CD-ROM";
+ const char *pszProductLevel = "1.0";
+ int rcTmp = vscsiLunQueryInqStrings(pVScsiLun, &pszVendorId, &pszProductId, &pszProductLevel);
+ Assert(RT_SUCCESS(rcTmp) || rcTmp == VERR_NOT_FOUND); RT_NOREF(rcTmp);
+
+ scsiPadStrS(ScsiInquiryReply.achVendorId, pszVendorId, 8);
+ scsiPadStrS(ScsiInquiryReply.achProductId, pszProductId, 16);
+ scsiPadStrS(ScsiInquiryReply.achProductLevel, pszProductLevel, 4);
RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
index 4b5217c..a837f7c 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
@@ -230,9 +230,16 @@ static DECLCALLBACK(int) vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQ
ScsiInquiryReply.u3AnsiVersion = 0x05; /* SPC-4 compliant */
ScsiInquiryReply.fCmdQue = 1; /* Command queuing supported. */
ScsiInquiryReply.fWBus16 = 1;
- scsiPadStrS(ScsiInquiryReply.achVendorId, "VBOX", 8);
- scsiPadStrS(ScsiInquiryReply.achProductId, "HARDDISK", 16);
- scsiPadStrS(ScsiInquiryReply.achProductLevel, "1.0", 4);
+
+ const char *pszVendorId = "VBOX";
+ const char *pszProductId = "HARDDISK";
+ const char *pszProductLevel = "1.0";
+ int rcTmp = vscsiLunQueryInqStrings(pVScsiLun, &pszVendorId, &pszProductId, &pszProductLevel);
+ Assert(RT_SUCCESS(rcTmp) || rcTmp == VERR_NOT_FOUND); RT_NOREF(rcTmp);
+
+ scsiPadStrS(ScsiInquiryReply.achVendorId, pszVendorId, 8);
+ scsiPadStrS(ScsiInquiryReply.achProductId, pszProductId, 16);
+ scsiPadStrS(ScsiInquiryReply.achProductLevel, pszProductLevel, 4);
RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
diff --git a/src/VBox/Devices/USB/VUSBDevice.cpp b/src/VBox/Devices/USB/VUSBDevice.cpp
index ffbdff4..b359242 100644
--- a/src/VBox/Devices/USB/VUSBDevice.cpp
+++ b/src/VBox/Devices/USB/VUSBDevice.cpp
@@ -308,9 +308,11 @@ static bool vusbDevStdReqSetConfig(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup,
vusbDevSetState(pDev, VUSB_DEVICE_STATE_CONFIGURED);
if (pDev->pUsbIns->pReg->pfnUsbSetConfiguration)
{
+ RTCritSectEnter(&pDev->pHub->pRootHub->CritSectDevices);
int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetConfiguration, 5,
pDev->pUsbIns, pNewCfgDesc->Core.bConfigurationValue,
pDev->pCurCfgDesc, pDev->paIfStates, pNewCfgDesc);
+ RTCritSectLeave(&pDev->pHub->pRootHub->CritSectDevices);
if (RT_FAILURE(rc))
{
Log(("vusb: error: %s: failed to set config %i (%Rrc) !!!\n", pDev->pUsbIns->pszName, iCfg, rc));
@@ -456,7 +458,9 @@ static bool vusbDevStdReqSetInterface(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
if (pDev->pUsbIns->pReg->pfnUsbSetInterface)
{
+ RTCritSectEnter(&pDev->pHub->pRootHub->CritSectDevices);
int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbSetInterface, 3, pDev->pUsbIns, iIf, iAlt);
+ RTCritSectLeave(&pDev->pHub->pRootHub->CritSectDevices);
if (RT_FAILURE(rc))
{
LogFlow(("vusbDevStdReqSetInterface: error: %s: couldn't find alt interface %u.%u (%Rrc)\n", pDev->pUsbIns->pszName, iIf, iAlt, rc));
@@ -528,8 +532,10 @@ static bool vusbDevStdReqClearFeature(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetu
&& pSetup->wValue == 0 /* ENDPOINT_HALT */
&& pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint)
{
+ RTCritSectEnter(&pDev->pHub->pRootHub->CritSectDevices);
int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)pDev->pUsbIns->pReg->pfnUsbClearHaltedEndpoint,
2, pDev->pUsbIns, pSetup->wIndex);
+ RTCritSectLeave(&pDev->pHub->pRootHub->CritSectDevices);
return RT_SUCCESS(rc);
}
break;
diff --git a/src/VBox/Devices/VirtIO/Virtio.cpp b/src/VBox/Devices/VirtIO/Virtio.cpp
index 9bf09bc..ca172ca 100644
--- a/src/VBox/Devices/VirtIO/Virtio.cpp
+++ b/src/VBox/Devices/VirtIO/Virtio.cpp
@@ -578,7 +578,16 @@ int vpciIOPortOut(PPDMDEVINS pDevIns,
if (u32 == 0)
rc = pCallbacks->pfnReset(pState);
else if (fHasBecomeReady)
+ {
+ /* Older hypervisors were lax and did not enforce bus mastering. Older guests
+ * (Linux prior to 2.6.34, NetBSD 6.x) were lazy and did not enable bus mastering.
+ * We automagically enable bus mastering on driver initialization to make existing
+ * drivers work.
+ */
+ PDMPciDevSetCommand(&pState->pciDevice, PDMPciDevGetCommand(&pState->pciDevice) | PCI_COMMAND_BUSMASTER);
+
pCallbacks->pfnReady(pState);
+ }
break;
default:
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 92a6bcf..87b3f9f 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -1841,7 +1841,6 @@ int main()
GEN_CHECK_SIZE(HDASTREAMSTATE);
GEN_CHECK_OFF(HDASTREAMSTATE, uCurBDLE);
GEN_CHECK_OFF(HDASTREAMSTATE, fInReset);
- GEN_CHECK_OFF(HDASTREAMSTATE, CritSect);
GEN_CHECK_OFF(HDASTREAMSTATE, Mapping);
GEN_CHECK_OFF(HDASTREAMSTATE, BDLE);
GEN_CHECK_OFF(HDASTREAMSTATE, pCircBuf);
@@ -1859,6 +1858,7 @@ int main()
GEN_CHECK_OFF(HDASTREAM, u16LVI);
GEN_CHECK_OFF(HDASTREAM, State);
GEN_CHECK_OFF(HDASTREAM, Dbg);
+ GEN_CHECK_OFF(HDASTREAM, CritSect);
GEN_CHECK_SIZE(HDASTATE);
GEN_CHECK_OFF(HDASTATE, PciDev);
@@ -1881,7 +1881,6 @@ int main()
GEN_CHECK_OFF(HDASTATE, fR0Enabled);
GEN_CHECK_OFF(HDASTATE, fRCEnabled);
#ifndef VBOX_WITH_AUDIO_CALLBACKS
- GEN_CHECK_OFF(HDASTATE, pTimer);
#endif
#ifdef VBOX_WITH_STATISTICS
# ifndef VBOX_WITH_AUDIO_CALLBACKS
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
index 11c9de7..3d416ae 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
@@ -513,6 +513,7 @@ void printUsage(USAGECATEGORY fCategory, uint32_t fSubCategory, PRTSTREAM pStrm)
" [--longmode on|off]\n"
" [--ibpb-on-vm-exit on|off]\n"
" [--ibpb-on-vm-entry on|off]\n"
+ " [--spec-ctrl on|off]\n"
" [--cpu-profile \"host|Intel 80[86|286|386]\"]\n"
" [--cpuid-portability-level <0..3>\n"
" [--cpuid-set <leaf[:subleaf]> <eax> <ebx> <ecx> <edx>]\n"
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
index 6dd1b76..89dc4c6 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
@@ -76,6 +76,7 @@ enum
MODIFYVM_VTXUX,
MODIFYVM_IBPB_ON_VM_EXIT,
MODIFYVM_IBPB_ON_VM_ENTRY,
+ MODIFYVM_SPEC_CTRL,
MODIFYVM_CPUS,
MODIFYVM_CPUHOTPLUG,
MODIFYVM_CPU_PROFILE,
@@ -258,6 +259,7 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
{ "--vtxux", MODIFYVM_VTXUX, RTGETOPT_REQ_BOOL_ONOFF },
{ "--ibpb-on-vm-exit", MODIFYVM_IBPB_ON_VM_EXIT, RTGETOPT_REQ_BOOL_ONOFF },
{ "--ibpb-on-vm-entry", MODIFYVM_IBPB_ON_VM_ENTRY, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--spec-ctrl", MODIFYVM_SPEC_CTRL, RTGETOPT_REQ_BOOL_ONOFF },
{ "--cpuid-set", MODIFYVM_SETCPUID, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX },
{ "--cpuid-remove", MODIFYVM_DELCPUID, RTGETOPT_REQ_UINT32_OPTIONAL_PAIR | RTGETOPT_FLAG_HEX },
{ "--cpuidset", MODIFYVM_SETCPUID_OLD, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX },
@@ -804,6 +806,10 @@ RTEXITCODE handleModifyVM(HandlerArg *a)
CHECK_ERROR(sessionMachine, SetCPUProperty(CPUPropertyType_IBPBOnVMEntry, ValueUnion.f));
break;
+ case MODIFYVM_SPEC_CTRL:
+ CHECK_ERROR(sessionMachine, SetCPUProperty(CPUPropertyType_SpecCtrl, ValueUnion.f));
+ break;
+
case MODIFYVM_CPUS:
{
CHECK_ERROR(sessionMachine, COMSETTER(CPUCount)(ValueUnion.u32));
diff --git a/src/VBox/Frontends/VirtualBox/Makefile.kmk b/src/VBox/Frontends/VirtualBox/Makefile.kmk
index 533ac90..75c69cf 100644
--- a/src/VBox/Frontends/VirtualBox/Makefile.kmk
+++ b/src/VBox/Frontends/VirtualBox/Makefile.kmk
@@ -933,13 +933,6 @@ VirtualBox_SOURCES += VirtualBox1_hidpi.qrc
VirtualBox1_hidpi.qrc_RCCFLAGS = -name BASIC1_HIDPI
VirtualBox_SOURCES += VirtualBox2_hidpi.qrc
VirtualBox2_hidpi.qrc_RCCFLAGS = -name BASIC2_HIDPI
-ifeq ($(KBUILD_TARGET),darwin)
- VirtualBox_SOURCES += VirtualBoxMac.qrc
- VirtualBoxMac.qrc_RCCFLAGS = -name MAC
-else
- VirtualBox_SOURCES += VirtualBoxOther.qrc
- VirtualBoxOther.qrc_RCCFLAGS = -name OTHER
-endif
VirtualBox_SOURCES += $(VBOX_VIRTUALBOX4_OUT_DIR)/VirtualBoxBrand.qrc
$(VBOX_VIRTUALBOX4_OUT_DIR)/VirtualBoxBrand.qrc_RCCFLAGS = -name BRAND
if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_GUI_USE_QGL)
diff --git a/src/VBox/Frontends/VirtualBox/VirtualBoxMac.qrc b/src/VBox/Frontends/VirtualBox/VirtualBoxMac.qrc
deleted file mode 100644
index 52757b6..0000000
--- a/src/VBox/Frontends/VirtualBox/VirtualBoxMac.qrc
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
- <qresource prefix="/">
- <file alias="vmw_new_welcome_bg.png">images/vmw_new_welcome_bg.png</file>
- <file alias="vmw_new_harddisk_bg.png">images/vmw_new_harddisk_bg.png</file>
- <file alias="vmw_first_run_bg.png">images/vmw_first_run_bg.png</file>
- <file alias="vmw_ovf_import_bg.png">images/vmw_ovf_import_bg.png</file>
- <file alias="vmw_ovf_export_bg.png">images/vmw_ovf_export_bg.png</file>
- <file alias="vmw_clone_bg.png">images/vmw_clone_bg.png</file>
- <file alias="monitor.png">images/monitor.png</file>
- <file alias="monitor_glossy.png">images/monitor_glossy.png</file>
- </qresource>
- </RCC>
diff --git a/src/VBox/Frontends/VirtualBox/VirtualBoxOther.qrc b/src/VBox/Frontends/VirtualBox/VirtualBoxOther.qrc
deleted file mode 100644
index 2f2da6d..0000000
--- a/src/VBox/Frontends/VirtualBox/VirtualBoxOther.qrc
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
- <qresource prefix="/">
- <file alias="vmw_new_welcome.png">images/vmw_new_welcome.png</file>
- <file alias="vmw_new_harddisk.png">images/vmw_new_harddisk.png</file>
- <file alias="vmw_first_run.png">images/vmw_first_run.png</file>
- <file alias="vmw_ovf_export.png">images/vmw_ovf_export.png</file>
- <file alias="vmw_ovf_import.png">images/vmw_ovf_import.png</file>
- <file alias="vmw_clone.png">images/vmw_clone.png</file>
- </qresource>
- </RCC>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
index 114dab8..2480303 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
@@ -2375,7 +2375,7 @@
<context>
<name>UIDownloaderAdditions</name>
<message>
- <location filename="../src/net/UIDownloaderAdditions.cpp" line="+200"/>
+ <location filename="../src/net/UIDownloaderAdditions.cpp" line="+182"/>
<source>Select folder to save Guest Additions image to</source>
<translation>Hautatu Gonbidatu Gehigarri irudia gordetzeko agiritegia</translation>
</message>
@@ -2388,7 +2388,7 @@
<context>
<name>UIDownloaderExtensionPack</name>
<message>
- <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+184"/>
+ <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+183"/>
<source>Select folder to save %1 to</source>
<translation>Hautatu %1 gordetzeko agiritegia</translation>
</message>
@@ -2401,7 +2401,7 @@
<context>
<name>UIDownloaderUserManual</name>
<message>
- <location filename="../src/net/UIDownloaderUserManual.cpp" line="+119"/>
+ <location filename="../src/net/UIDownloaderUserManual.cpp" line="+125"/>
<source>Select folder to save User Manual to</source>
<translation>Hautatu Erabiltzaile Eskuliburua gordetzeko agiritegia</translation>
</message>
@@ -11024,7 +11024,7 @@
<context>
<name>UINetworkReplyPrivate</name>
<message>
- <location filename="../src/net/UINetworkReply.cpp" line="+957"/>
+ <location filename="../src/net/UINetworkReply.cpp" line="+965"/>
<source>Host not found</source>
<translation>Hostalaria ez da aurkitu</translation>
</message>
@@ -11088,7 +11088,7 @@
<context>
<name>UINetworkReplyPrivateThread</name>
<message>
- <location line="-579"/>
+ <location line="-590"/>
<source>During proxy configuration</source>
<translation>Proxy itxurapenean zehar</translation>
</message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
index 4f68a7b..18fde9a 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
@@ -2550,27 +2550,27 @@
<message>
<source>Result Code: </source>
<comment>error info</comment>
- <translation type="unfinished">Kode Hasil: </translation>
+ <translation>Kode Hasil: </translation>
</message>
<message>
<source>Component: </source>
<comment>error info</comment>
- <translation type="unfinished">Komponen: </translation>
+ <translation>Komponen: </translation>
</message>
<message>
<source>Interface: </source>
<comment>error info</comment>
- <translation type="unfinished">Antar Muka: </translation>
+ <translation>Antar Muka: </translation>
</message>
<message>
<source>Callee: </source>
<comment>error info</comment>
- <translation type="unfinished"></translation>
+ <translation>Yang Dipanggil: </translation>
</message>
<message>
<source>Callee RC: </source>
<comment>error info</comment>
- <translation type="unfinished"></translation>
+ <translation>RC Yang Dipanggil: </translation>
</message>
</context>
<context>
@@ -5277,11 +5277,11 @@
</message>
<message>
<source>Adding network...</source>
- <translation type="unfinished"></translation>
+ <translation>Menambah jaringan...</translation>
</message>
<message>
<source>Removing network...</source>
- <translation type="unfinished"></translation>
+ <translation>Menghapus jaringan...</translation>
</message>
</context>
<context>
@@ -6772,11 +6772,11 @@
</message>
<message>
<source>When checked, VirtualBox will record the audio stream to video file as well.</source>
- <translation type="unfinished"></translation>
+ <translation>Saat dicentang, VirtualBox juga akan merekam stream audio ke berkas video.</translation>
</message>
<message>
<source>&Record Audio</source>
- <translation type="unfinished"></translation>
+ <translation>&Rekam Audio</translation>
</message>
</context>
<context>
@@ -8981,35 +8981,35 @@
</message>
<message>
<source>Choose Medium Location</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih Lokasi Medium</translation>
</message>
<message>
<source>Location can not be empty.</source>
- <translation type="unfinished"></translation>
+ <translation>Lokasi tidak boleh kosong.</translation>
</message>
<message>
<source>This type of medium is attached directly or indirectly, preserved when taking snapshots.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara langsung atau tak langsung, dilestarikan ketika mengambil snapshot.</translation>
+ <translation>Tipe medium ini dicantol secara langsung atau tak langsung, dilestarikan ketika mengambil snapshot.</translation>
</message>
<message>
<source>This type of medium is attached indirectly, changes are wiped out the next time the virtual machine is started.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara tak langsung, perubahan disapu habis saat mesin virtual dijalankan berikutnya.</translation>
+ <translation>Tipe medium ini dicantol secara tak langsung, perubahan disapu habis saat mesin virtual dijalankan berikutnya.</translation>
</message>
<message>
<source>This type of medium is attached directly, ignored when taking snapshots.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara langsung, diabaikan ketika mengambil snapshot.</translation>
+ <translation>Tipe medium ini dicantol secara langsung, diabaikan ketika mengambil snapshot.</translation>
</message>
<message>
<source>This type of medium is attached directly, allowed to be used concurrently by several machines.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara langsung, diijinkan untuk dipakai bersamaan oleh beberapa mesin.</translation>
+ <translation>Tipe medium ini dicantol secara langsung, diizinkan untuk dipakai bersamaan oleh beberapa mesin.</translation>
</message>
<message>
<source>This type of medium is attached directly, and can be used by several machines.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara langsung, dan dapat dipakai oleh beberapa mesin.</translation>
+ <translation>Tipe medium ini dicantol secara langsung, dan dapat dipakai oleh beberapa mesin.</translation>
</message>
<message>
<source>This type of medium is attached indirectly, so that one base medium can be used for several VMs which have their own differencing medium to store their modifications.</source>
- <translation type="unfinished">Tipe medium ini dicantol secara tak langsung, sehingga satu medium basis dapat dipakai bagi beberapa VM yang memiliki medium pembeda masing-masing untuk menyimpan perubahan mereka.</translation>
+ <translation>Tipe medium ini dicantol secara tak langsung, sehingga satu medium basis dapat dipakai bagi beberapa VM yang memiliki medium pembeda masing-masing untuk menyimpan perubahan mereka.</translation>
</message>
</context>
<context>
@@ -9190,43 +9190,43 @@
</message>
<message>
<source>Copy Disk Image File (%1)</source>
- <translation type="unfinished">Salin Berkas Image Disk (%1)</translation>
+ <translation>Salin Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Remove Disk Image File (%1)</source>
- <translation type="unfinished">Hapus Berkas Image Disk (%1)</translation>
+ <translation>Hapus Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Release Disk Image File (%1)</source>
- <translation type="unfinished">Lepas Berkas Image Disk (%1)</translation>
+ <translation>Lepas Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Open Disk Image File Properties (%1)</source>
- <translation type="unfinished">Buka Properti Berkas Image Disk (%1)</translation>
+ <translation>Buka Properti Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Refresh Disk Image Files (%1)</source>
- <translation type="unfinished">Segarkan Berkas Image Disk (%1)</translation>
+ <translation>Segarkan Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Current extension (*.%1)</source>
- <translation type="unfinished"></translation>
+ <translation>Ekstensi saat ini (*.%1)</translation>
</message>
<message>
<source>Choose the location of this medium</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih lokasi medium ini</translation>
</message>
<message>
<source>&Move...</source>
- <translation type="unfinished"></translation>
+ <translation>Pi&ndah...</translation>
</message>
<message>
<source>Move Disk Image File (%1)</source>
- <translation type="unfinished"></translation>
+ <translation>Pindahkan Berkas Image Disk (%1)</translation>
</message>
<message>
<source>Move selected disk image file</source>
- <translation type="unfinished"></translation>
+ <translation>Pindahkan berkas image disk yang dipilih</translation>
</message>
</context>
<context>
@@ -11251,19 +11251,19 @@
</message>
<message>
<source><p>Could not insert the <b>%1</b> disk image file into the virtual machine <b>%2</b>, as the machine has no optical drives. Please add a drive using the storage page of the virtual machine settings window.</p></source>
- <translation type="unfinished"></translation>
+ <translation><b>Tak bisa menyisipkan berkas image disk <b>%1</b> ke dalam mesin virtual <b>%2</b>, karena mesin tak memiliki drive optik. Silakan tambahkan sebuah drive memakai halaman penyimpanan dari jendela pengaturan mesin virtual.</p></translation>
</message>
<message>
<source>Failed to change the snapshot <b>%1</b> of the virtual machine <b>%2</b>.</source>
- <translation type="unfinished"></translation>
+ <translation>Gagal mengubah snapshot <b>%1</b> dari mesin virtual <b>%2</b>.</translation>
</message>
<message>
<source>Failed to create the virtual disk image storage <nobr><b>%1</b>.</nobr></source>
- <translation type="unfinished"></translation>
+ <translation>Gagal menciptakan penyimpanan image hard disk virtual <nobr><b>%1</b>.</nobr></translation>
</message>
<message>
<source><p>The changes you requested require this disk to be released from the machines it is attached to.</p><p>Are you sure you want to release the disk image file <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>Perubahan yang Anda minta memerlukan disk ini dilepas dari mesin-mesin tempat itu dicantolkan.</p><p>Anda yakin hendak melepas berkas image disk <nobr>><b>%1</b></nobr>?</p><p>Ini akan melepasnya dari mesin-mesin virtual berikut: <b>%2</b>.</p></translation>
</message>
</context>
<context>
@@ -12215,11 +12215,11 @@ langkah ini dan memasang hard disk pada waktu lain menggunakan dialog Setting Me
<name>UIPopupPane</name>
<message>
<source><p><b>Details:</b></source>
- <translation type="unfinished"></translation>
+ <translation><p><b>Rincian:</b></translation>
</message>
<message>
<source><p><b>Details:</b> (%1 of %2)</source>
- <translation type="unfinished"></translation>
+ <translation><p><b>Rincian:</b> (%1 dari %2)</translation>
</message>
</context>
<context>
@@ -12619,23 +12619,23 @@ langkah ini dan memasang hard disk pada waktu lain menggunakan dialog Setting Me
</message>
<message>
<source>Enter a name for the new snapshot...</source>
- <translation type="unfinished"></translation>
+ <translation>Masukkan suatu nama bagi snapshot baru...</translation>
</message>
<message>
<source>Enter a name for this snapshot...</source>
- <translation type="unfinished"></translation>
+ <translation>Masukkan suatu nama untuk snapshot ini...</translation>
</message>
<message>
<source>Take</source>
- <translation type="unfinished"></translation>
+ <translation>Ambil</translation>
</message>
<message>
<source>Take snapshot on the basis of current machine state</source>
- <translation type="unfinished"></translation>
+ <translation>Ambil snapshot pada basis dari keadaan mesin saat ini</translation>
</message>
<message>
<source>Take Snapshot (%1)</source>
- <translation type="unfinished">Ambil Snapshot (%1)</translation>
+ <translation>Ambil Snapshot (%1)</translation>
</message>
</context>
<context>
@@ -13486,76 +13486,76 @@ langkah ini dan memasang hard disk pada waktu lain menggunakan dialog Setting Me
</message>
<message>
<source>Copy Virtual Disk Image</source>
- <translation type="unfinished"></translation>
+ <translation>Salin Image Disk Virtual</translation>
</message>
<message>
<source>Disk image to copy</source>
- <translation type="unfinished"></translation>
+ <translation>Image disk yang akan disalin</translation>
</message>
<message>
<source><p>Please select the virtual disk image file that you would like to copy if it is not already selected. You can either choose one from the list or use the folder icon beside the list to select one.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Silakan pilih berkas image disk virtual yang ingin Anda salin bila belum dipilih. Anda dapat memilih dari daftar atau memakai ikon folder di samping daftar untuk memilih salah satu.</p></translation>
</message>
<message>
<source>Choose a virtual disk image file to copy...</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih berkas image disk virtual yang akan disalin...</translation>
</message>
<message>
<source>Disk image file type</source>
- <translation type="unfinished"></translation>
+ <translation>Tipe berkas image disk</translation>
</message>
<message>
<source>Please choose the type of file that you would like to use for the new virtual disk image. If you do not need to use it with other virtualization software you can leave this setting unchanged.</source>
- <translation type="unfinished"></translation>
+ <translation>Silakan pilih tipe berkas yang ingin Anda pakai untuk image disk virtual baru. Bila Anda tak perlu memakainya dengan perangkat lunak virtualisasi lain Anda dapat membiarkan pengaturan ini tak diubah.</translation>
</message>
<message>
<source>Please choose whether the new virtual disk image file should grow as it is used (dynamically allocated) or if it should be created at its maximum size (fixed size).</source>
- <translation type="unfinished"></translation>
+ <translation>Silakan pilih apakah berkas image disk virtual baru mesti tumbuh ketika dipakai (dialokasikan secara dinamik) atau mesti diciptakan pada ukuran maksimumnya (ukuran tetap).</translation>
</message>
<message>
<source><p>A <b>dynamically allocated</b> disk image file will only use space on your physical hard disk as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Berkas image disk <b>yang dialokasikan secara dinamik</b> hanya akan memakai ruang pada hard disk fisik Anda ketika terisi (sampai dengan suatu <b>ukuran tetap</b> maksimum), walaupun mereka tak akan mengecil lagi secara otomatis ketika ruang di dalamnya dibebaskan.</p></translation>
</message>
<message>
<source><p>A <b>fixed size</b> disk image file may take longer to create on some systems but is often faster to use.</p></source>
- <translation type="unfinished"></translation>
+ <translation><p>Berkas image disk virtual <b>ukuran tetap</b> mungkin makan waktu lebih lama untuk diciptakan pada beberapa sistem tapi seringkali lebih cepat dipakainya.</p></translation>
</message>
<message>
<source><p>You can also choose to <b>split</b> the disk image 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 type="unfinished"></translation>
+ <translation><p>Anda juga dapat memilih untuk <b>memecah</b> berkas image disk ke dalam beberapa berkas yang masing-masing berukuran sampai dengan dua giga byte. Ini terutama berguna bila Anda hendak menyimpan mesin virtual pada peranti USB lepas pasang atau sistem lama, yang mungkin tak bisa menangani berkas sangat besar.</translation>
</message>
<message>
<source>Please choose a location for new virtual disk image file</source>
- <translation type="unfinished"></translation>
+ <translation>Harap pilih lokasi untuk berkas image disk virtual baru</translation>
</message>
<message>
<source>New disk image to create</source>
- <translation type="unfinished"></translation>
+ <translation>Image disk baru yang akan dibuat</translation>
</message>
<message>
<source>Please type the name of the new virtual disk image file into the box below or click on the folder icon to select a different folder to create the file in.</source>
- <translation type="unfinished"></translation>
+ <translation>Silakan ketik nama berkas image disk virtual baru ke kotak di bawah atau klik pada ikon folder untuk memilih folder lain tempat mencipta berkas.</translation>
</message>
<message>
<source>Choose a location for new virtual disk image file...</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih lokasi untuk berkas image disk virtual baru...</translation>
</message>
<message>
<source>%1_copy</source>
<comment>copied virtual disk image name</comment>
- <translation type="unfinished">salinan_%1</translation>
+ <translation>salinan_%1</translation>
</message>
<message>
<source>Disk image to ©</source>
- <translation type="unfinished"></translation>
+ <translation>Image disk yang akan di&salin</translation>
</message>
<message>
<source>&New disk image to create</source>
- <translation type="unfinished"></translation>
+ <translation>Image disk baru ya&ng akan dibuat</translation>
</message>
<message>
<source>Disk image file &type</source>
- <translation type="unfinished"></translation>
+ <translation>&Tipe berkas image disk</translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
index c353576..4e01778 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
@@ -1712,7 +1712,7 @@
<context>
<name>UIDownloaderAdditions</name>
<message>
- <location filename="../src/net/UIDownloaderAdditions.cpp" line="+200"/>
+ <location filename="../src/net/UIDownloaderAdditions.cpp" line="+182"/>
<source>Select folder to save Guest Additions image to</source>
<translation>Izberite mapo za shranjevanje programa Guest Additions</translation>
</message>
@@ -1725,7 +1725,7 @@
<context>
<name>UIDownloaderExtensionPack</name>
<message>
- <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+184"/>
+ <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+183"/>
<source>Select folder to save %1 to</source>
<translation>Izberite mapo za shranjevanje %1</translation>
</message>
@@ -1738,7 +1738,7 @@
<context>
<name>UIDownloaderUserManual</name>
<message>
- <location filename="../src/net/UIDownloaderUserManual.cpp" line="+119"/>
+ <location filename="../src/net/UIDownloaderUserManual.cpp" line="+125"/>
<source>Select folder to save User Manual to</source>
<translation>Izberite mapo za shranjevanje uporabniškega priročnika</translation>
</message>
@@ -9131,7 +9131,7 @@
<context>
<name>UINetworkReplyPrivate</name>
<message>
- <location filename="../src/net/UINetworkReply.cpp" line="+957"/>
+ <location filename="../src/net/UINetworkReply.cpp" line="+965"/>
<source>Host not found</source>
<translation>Gostitelj ni bil najden</translation>
</message>
@@ -9195,7 +9195,7 @@
<context>
<name>UINetworkReplyPrivateThread</name>
<message>
- <location line="-570"/>
+ <location line="-581"/>
<source>During proxy configuration</source>
<translation>Med nastavitvijo posredniškega strežnika</translation>
</message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/qt_id.ts b/src/VBox/Frontends/VirtualBox/nls/qt_id.ts
index 8719003..0b050c3 100644
--- a/src/VBox/Frontends/VirtualBox/nls/qt_id.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/qt_id.ts
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.1" language="id_ID">
+<TS version="2.0" language="id_ID">
<context>
<name>AudioOutput</name>
<message>
<source><html>The audio playback device <b>%1</b> does not work.<br/>Falling back to <b>%2</b>.</html></source>
- <translation type="vanished"><html>Perangkat pemutar audio <b>%1</b> tak bekerja.<br/>Beralih ke cadangan <b>%2</b>.</html></translation>
+ <translation><html>Perangkat pemutar audio <b>%1</b> tak bekerja.<br/>Beralih ke cadangan <b>%2</b>.</html></translation>
</message>
<message>
<source><html>Switching to the audio playback device <b>%1</b><br/>which just became available and has higher preference.</html></source>
- <translation type="vanished"><html>Bertukar ke perangkat pemutar audio <b>%1</b><br/>yang baru saja jadi tersedia dan memiliki preferensi lebih tinggi.</html></translation>
+ <translation><html>Bertukar ke perangkat pemutar audio <b>%1</b><br/>yang baru saja jadi tersedia dan memiliki preferensi lebih tinggi.</html></translation>
</message>
<message>
<source>Revert back to device '%1'</source>
- <translation type="vanished">Kembali ke perangkat '%1'</translation>
+ <translation>Kembali ke perangkat '%1'</translation>
</message>
</context>
<context>
<name>CloseButton</name>
<message>
<source>Close Tab</source>
- <translation type="unfinished"></translation>
+ <translation>Tutup Tab</translation>
</message>
</context>
<context>
@@ -58,27 +58,27 @@
<name>Phonon::</name>
<message>
<source>Notifications</source>
- <translation type="vanished">Pemberitahuan</translation>
+ <translation>Pemberitahuan</translation>
</message>
<message>
<source>Music</source>
- <translation type="vanished">Musik</translation>
+ <translation>Musik</translation>
</message>
<message>
<source>Video</source>
- <translation type="vanished">Video</translation>
+ <translation>Video</translation>
</message>
<message>
<source>Communication</source>
- <translation type="vanished">Komunikasi</translation>
+ <translation>Komunikasi</translation>
</message>
<message>
<source>Games</source>
- <translation type="vanished">Permainan</translation>
+ <translation>Permainan</translation>
</message>
<message>
<source>Accessibility</source>
- <translation type="vanished">Aksesibilitas</translation>
+ <translation>Aksesibilitas</translation>
</message>
</context>
<context>
@@ -86,13 +86,13 @@
<message>
<source>Warning: You do not seem to have the package gstreamer0.10-plugins-good installed.
Some video features have been disabled.</source>
- <translation type="vanished">Peringatan: Sepertinya Anda belum memasang paket gstreamer0.10-plugins-good.
+ <translation>Peringatan: Sepertinya Anda belum memasang paket gstreamer0.10-plugins-good.
Beberapa fitur video telah dimatikan.</translation>
</message>
<message>
<source>Warning: You do not seem to have the base GStreamer plugins installed.
All audio and video support has been disabled</source>
- <translation type="vanished">Peringatan: Sepertinya Anda belum memasang plugin GStreamer dasar.
+ <translation>Peringatan: Sepertinya Anda belum memasang plugin GStreamer dasar.
Semua dukungan audio dan video telah dimatikan</translation>
</message>
</context>
@@ -103,322 +103,322 @@
Check your Gstreamer installation and make sure you
have libgstreamer-plugins-base installed.</source>
- <translation type="vanished">Tak bisa mulai memutar.
+ <translation>Tak bisa mulai memutar.
Periksa instalasi Gstreamer Anda dan pastikan bahwa
libgstreamer-plugins-base telah terpasang.</translation>
</message>
<message numerus="yes">
<source>A required codec is missing. You need to install the following codec(s) to play this content: %0</source>
- <translation type="vanished">
+ <translation>
<numerusform>Sebuah codec yang diperlukan hilang. Anda perlu memasang codec berikut untuk memainkannya: %0</numerusform>
</translation>
</message>
<message>
<source>Could not open media source.</source>
- <translation type="vanished">Tak bisa membuka sumber media.</translation>
+ <translation>Tak bisa membuka sumber media.</translation>
</message>
<message>
<source>Invalid source type.</source>
- <translation type="vanished">Tipe sumber tak valid.</translation>
+ <translation>Tipe sumber tak valid.</translation>
</message>
<message>
<source>Could not locate media source.</source>
- <translation type="vanished">Tak bisa menemukan sumber media.</translation>
+ <translation>Tak bisa menemukan sumber media.</translation>
</message>
<message>
<source>Could not open audio device. The device is already in use.</source>
- <translation type="vanished">Tak bisa membuka perangkat audio. Perangkat telah dipakai.</translation>
+ <translation>Tak bisa membuka perangkat audio. Perangkat telah dipakai.</translation>
</message>
<message>
<source>Could not decode media source.</source>
- <translation type="vanished">Tak bisa men-decode sumber media.</translation>
+ <translation>Tak bisa men-decode sumber media.</translation>
</message>
</context>
<context>
<name>Phonon::VolumeSlider</name>
<message>
<source>Volume: %1%</source>
- <translation type="vanished">Volume: %1%</translation>
+ <translation>Volume: %1%</translation>
</message>
<message>
<source>Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%</source>
- <translation type="vanished">Gunakan penggeser ini untuk mengatur keras suara. Posisi paling kiri adalah 0%, paling kanan %1%</translation>
+ <translation>Gunakan penggeser ini untuk mengatur keras suara. Posisi paling kiri adalah 0%, paling kanan %1%</translation>
</message>
</context>
<context>
<name>Q3Accel</name>
<message>
<source>%1, %2 not defined</source>
- <translation type="vanished">%1, %2 tak didefinisikan</translation>
+ <translation>%1, %2 tak didefinisikan</translation>
</message>
<message>
<source>Ambiguous %1 not handled</source>
- <translation type="vanished">%1 ambigu tak ditangani</translation>
+ <translation>%1 ambigu tak ditangani</translation>
</message>
</context>
<context>
<name>Q3DataTable</name>
<message>
<source>True</source>
- <translation type="vanished">Benar</translation>
+ <translation>Benar</translation>
</message>
<message>
<source>False</source>
- <translation type="vanished">Salah</translation>
+ <translation>Salah</translation>
</message>
<message>
<source>Insert</source>
- <translation type="vanished">Sisipkan</translation>
+ <translation>Sisipkan</translation>
</message>
<message>
<source>Update</source>
- <translation type="vanished">Perbarui</translation>
+ <translation>Perbarui</translation>
</message>
<message>
<source>Delete</source>
- <translation type="vanished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
</context>
<context>
<name>Q3FileDialog</name>
<message>
<source>Copy or Move a File</source>
- <translation type="vanished">Salin atau Pindah sebuah File</translation>
+ <translation>Salin atau Pindah sebuah File</translation>
</message>
<message>
<source>Read: %1</source>
- <translation type="vanished">Baca: %1</translation>
+ <translation>Baca: %1</translation>
</message>
<message>
<source>Write: %1</source>
- <translation type="vanished">Tulis: %1</translation>
+ <translation>Tulis: %1</translation>
</message>
<message>
<source>Cancel</source>
- <translation type="vanished">Batal</translation>
+ <translation>Batal</translation>
</message>
<message>
<source>All Files (*)</source>
- <translation type="vanished">Semua File (*)</translation>
+ <translation>Semua File (*)</translation>
</message>
<message>
<source>Name</source>
- <translation type="vanished">Nama</translation>
+ <translation>Nama</translation>
</message>
<message>
<source>Size</source>
- <translation type="vanished">Ukuran</translation>
+ <translation>Ukuran</translation>
</message>
<message>
<source>Type</source>
- <translation type="vanished">Tipe</translation>
+ <translation>Tipe</translation>
</message>
<message>
<source>Date</source>
- <translation type="vanished">Tanggal</translation>
+ <translation>Tanggal</translation>
</message>
<message>
<source>Attributes</source>
- <translation type="vanished">Atribut</translation>
+ <translation>Atribut</translation>
</message>
<message>
<source>&OK</source>
- <translation type="vanished">&OK</translation>
+ <translation>&OK</translation>
</message>
<message>
<source>Look &in:</source>
- <translation type="vanished">Lihat d&i:</translation>
+ <translation>Lihat d&i:</translation>
</message>
<message>
<source>File &name:</source>
- <translation type="vanished">&Nama file:</translation>
+ <translation>&Nama file:</translation>
</message>
<message>
<source>File &type:</source>
- <translation type="vanished">&Tipe file:</translation>
+ <translation>&Tipe file:</translation>
</message>
<message>
<source>Back</source>
- <translation type="vanished">Mundur</translation>
+ <translation>Mundur</translation>
</message>
<message>
<source>One directory up</source>
- <translation type="vanished">Naik satu direktori</translation>
+ <translation>Naik satu direktori</translation>
</message>
<message>
<source>Create New Folder</source>
- <translation type="vanished">Buat Folder Baru</translation>
+ <translation>Buat Folder Baru</translation>
</message>
<message>
<source>List View</source>
- <translation type="vanished">Tilikan Daftar</translation>
+ <translation>Tilikan Daftar</translation>
</message>
<message>
<source>Detail View</source>
- <translation type="vanished">Tilikan Rinci</translation>
+ <translation>Tilikan Rinci</translation>
</message>
<message>
<source>Preview File Info</source>
- <translation type="vanished">Pratinjau Info File</translation>
+ <translation>Pratinjau Info File</translation>
</message>
<message>
<source>Preview File Contents</source>
- <translation type="vanished">Pratinjau Isi File</translation>
+ <translation>Pratinjau Isi File</translation>
</message>
<message>
<source>Read-write</source>
- <translation type="vanished">Baca-tulis</translation>
+ <translation>Baca-tulis</translation>
</message>
<message>
<source>Read-only</source>
- <translation type="vanished">Baca-saja</translation>
+ <translation>Baca-saja</translation>
</message>
<message>
<source>Write-only</source>
- <translation type="vanished">Tulis-saja</translation>
+ <translation>Tulis-saja</translation>
</message>
<message>
<source>Inaccessible</source>
- <translation type="vanished">Tak dapat diakses</translation>
+ <translation>Tak dapat diakses</translation>
</message>
<message>
<source>Symlink to File</source>
- <translation type="vanished">Symlink ke File</translation>
+ <translation>Symlink ke File</translation>
</message>
<message>
<source>Symlink to Directory</source>
- <translation type="vanished">Symlink ke Direktori</translation>
+ <translation>Symlink ke Direktori</translation>
</message>
<message>
<source>Symlink to Special</source>
- <translation type="vanished">Symlink ke Spesial</translation>
+ <translation>Symlink ke Spesial</translation>
</message>
<message>
<source>File</source>
- <translation type="vanished">File</translation>
+ <translation>File</translation>
</message>
<message>
<source>Dir</source>
- <translation type="vanished">Dir</translation>
+ <translation>Dir</translation>
</message>
<message>
<source>Special</source>
- <translation type="vanished">Spesial</translation>
+ <translation>Spesial</translation>
</message>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>Save As</source>
- <translation type="vanished">Simpan Sebagai</translation>
+ <translation>Simpan Sebagai</translation>
</message>
<message>
<source>&Open</source>
- <translation type="vanished">&Buka</translation>
+ <translation>&Buka</translation>
</message>
<message>
<source>&Save</source>
- <translation type="vanished">&Simpan</translation>
+ <translation>&Simpan</translation>
</message>
<message>
<source>&Rename</source>
- <translation type="vanished">&Ubah Nama</translation>
+ <translation>&Ubah Nama</translation>
</message>
<message>
<source>&Delete</source>
- <translation type="vanished">Hapu&s</translation>
+ <translation>Hapu&s</translation>
</message>
<message>
<source>R&eload</source>
- <translation type="vanished">Muat &Ulang</translation>
+ <translation>Muat &Ulang</translation>
</message>
<message>
<source>Sort by &Name</source>
- <translation type="vanished">Urut &Nama</translation>
+ <translation>Urut &Nama</translation>
</message>
<message>
<source>Sort by &Size</source>
- <translation type="vanished">Urut &Ukuran</translation>
+ <translation>Urut &Ukuran</translation>
</message>
<message>
<source>Sort by &Date</source>
- <translation type="vanished">Urut &Tanggal</translation>
+ <translation>Urut &Tanggal</translation>
</message>
<message>
<source>&Unsorted</source>
- <translation type="vanished">T&ak Diurutkan</translation>
+ <translation>T&ak Diurutkan</translation>
</message>
<message>
<source>Sort</source>
- <translation type="vanished">Urutkan</translation>
+ <translation>Urutkan</translation>
</message>
<message>
<source>Show &hidden files</source>
- <translation type="vanished">&Tampilkan file tersembunyi</translation>
+ <translation>&Tampilkan file tersembunyi</translation>
</message>
<message>
<source>the file</source>
- <translation type="vanished">file</translation>
+ <translation>file</translation>
</message>
<message>
<source>the directory</source>
- <translation type="vanished">direktori</translation>
+ <translation>direktori</translation>
</message>
<message>
<source>the symlink</source>
- <translation type="vanished">symlink</translation>
+ <translation>symlink</translation>
</message>
<message>
<source>Delete %1</source>
- <translation type="vanished">Hapus %1</translation>
+ <translation>Hapus %1</translation>
</message>
<message>
<source><qt>Are you sure you wish to delete %1 "%2"?</qt></source>
- <translation type="vanished"><qt>Anda yakin hendak menghapus %1 "%2"?</qt></translation>
+ <translation><qt>Anda yakin hendak menghapus %1 "%2"?</qt></translation>
</message>
<message>
<source>&Yes</source>
- <translation type="vanished">&Ya</translation>
+ <translation>&Ya</translation>
</message>
<message>
<source>&No</source>
- <translation type="vanished">&Tidak</translation>
+ <translation>&Tidak</translation>
</message>
<message>
<source>New Folder 1</source>
- <translation type="vanished">Folder Baru 1</translation>
+ <translation>Folder Baru 1</translation>
</message>
<message>
<source>New Folder</source>
- <translation type="vanished">Folder Baru</translation>
+ <translation>Folder Baru</translation>
</message>
<message>
<source>New Folder %1</source>
- <translation type="vanished">Folder Baru %1</translation>
+ <translation>Folder Baru %1</translation>
</message>
<message>
<source>Find Directory</source>
- <translation type="vanished">Cari Direktori</translation>
+ <translation>Cari Direktori</translation>
</message>
<message>
<source>Directories</source>
- <translation type="vanished">Direktori</translation>
+ <translation>Direktori</translation>
</message>
<message>
<source>Directory:</source>
- <translation type="vanished">Direktori:</translation>
+ <translation>Direktori:</translation>
</message>
<message>
<source>Error</source>
- <translation type="vanished">Kesalahan</translation>
+ <translation>Kesalahan</translation>
</message>
<message>
<source>%1
File not found.
Check path and filename.</source>
- <translation type="vanished">%1
+ <translation>%1
File tak ditemukan.
Periksa path dan nama file.</translation>
</message>
@@ -428,19 +428,19 @@ Periksa path dan nama file.</translation>
<message>
<source>Could not read directory
%1</source>
- <translation type="vanished">Tak bisa membaca direktori
+ <translation>Tak bisa membaca direktori
%1</translation>
</message>
<message>
<source>Could not create directory
%1</source>
- <translation type="vanished">Tak bisa membuat direktori
+ <translation>Tak bisa membuat direktori
%1</translation>
</message>
<message>
<source>Could not remove file or directory
%1</source>
- <translation type="vanished">Tak bisa menghapus file atau direktori
+ <translation>Tak bisa menghapus file atau direktori
%1</translation>
</message>
<message>
@@ -448,7 +448,7 @@ Periksa path dan nama file.</translation>
%1
to
%2</source>
- <translation type="vanished">Tak bisa mengubah nama
+ <translation>Tak bisa mengubah nama
%1
menjadi
%2</translation>
@@ -456,13 +456,13 @@ menjadi
<message>
<source>Could not open
%1</source>
- <translation type="vanished">Tak bisa membuka
+ <translation>Tak bisa membuka
%1</translation>
</message>
<message>
<source>Could not write
%1</source>
- <translation type="vanished">Tak bisa menulis
+ <translation>Tak bisa menulis
%1</translation>
</message>
</context>
@@ -470,203 +470,203 @@ menjadi
<name>Q3MainWindow</name>
<message>
<source>Line up</source>
- <translation type="vanished">Bariskan</translation>
+ <translation>Bariskan</translation>
</message>
<message>
<source>Customize...</source>
- <translation type="vanished">Gubah...</translation>
+ <translation>Gubah...</translation>
</message>
</context>
<context>
<name>Q3NetworkProtocol</name>
<message>
<source>Operation stopped by the user</source>
- <translation type="vanished">Operasi dihentikan oleh pengguna</translation>
+ <translation>Operasi dihentikan oleh pengguna</translation>
</message>
</context>
<context>
<name>Q3ProgressDialog</name>
<message>
<source>Cancel</source>
- <translation type="vanished">Batal</translation>
+ <translation>Batal</translation>
</message>
</context>
<context>
<name>Q3TabDialog</name>
<message>
<source>OK</source>
- <translation type="vanished">OK</translation>
+ <translation>OK</translation>
</message>
<message>
<source>Apply</source>
- <translation type="vanished">Terapkan</translation>
+ <translation>Terapkan</translation>
</message>
<message>
<source>Help</source>
- <translation type="vanished">Bantuan</translation>
+ <translation>Bantuan</translation>
</message>
<message>
<source>Defaults</source>
- <translation type="vanished">Bawaan</translation>
+ <translation>Bawaan</translation>
</message>
<message>
<source>Cancel</source>
- <translation type="vanished">Batal</translation>
+ <translation>Batal</translation>
</message>
</context>
<context>
<name>Q3TextEdit</name>
<message>
<source>&Undo</source>
- <translation type="vanished">&Batalkan</translation>
+ <translation>&Batalkan</translation>
</message>
<message>
<source>&Redo</source>
- <translation type="vanished">&Jadi Lagi</translation>
+ <translation>&Jadi Lagi</translation>
</message>
<message>
<source>Cu&t</source>
- <translation type="vanished">Po&tong</translation>
+ <translation>Po&tong</translation>
</message>
<message>
<source>&Copy</source>
- <translation type="vanished">&Salin</translation>
+ <translation>&Salin</translation>
</message>
<message>
<source>&Paste</source>
- <translation type="vanished">Tem&pel</translation>
+ <translation>Tem&pel</translation>
</message>
<message>
<source>Clear</source>
- <translation type="vanished">Bersihkan</translation>
+ <translation>Bersihkan</translation>
</message>
<message>
<source>Select All</source>
- <translation type="vanished">Pilih Semua</translation>
+ <translation>Pilih Semua</translation>
</message>
</context>
<context>
<name>Q3TitleBar</name>
<message>
<source>System</source>
- <translation type="vanished">Sistem</translation>
+ <translation>Sistem</translation>
</message>
<message>
<source>Restore up</source>
- <translation type="vanished">Kembali naik</translation>
+ <translation>Kembali naik</translation>
</message>
<message>
<source>Minimize</source>
- <translation type="vanished">Minimalkan</translation>
+ <translation>Minimalkan</translation>
</message>
<message>
<source>Restore down</source>
- <translation type="vanished">Kembali turun</translation>
+ <translation>Kembali turun</translation>
</message>
<message>
<source>Maximize</source>
- <translation type="vanished">Maksimalkan</translation>
+ <translation>Maksimalkan</translation>
</message>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Contains commands to manipulate the window</source>
- <translation type="vanished">Memuat perintah untuk memanipulasi window</translation>
+ <translation>Memuat perintah untuk memanipulasi window</translation>
</message>
<message>
<source>Puts a minimized back to normal</source>
- <translation type="vanished">Mengembalikan yang terminimumkan ke normal</translation>
+ <translation>Mengembalikan yang terminimumkan ke normal</translation>
</message>
<message>
<source>Moves the window out of the way</source>
- <translation type="vanished">Memindah window agar tak menghalangi</translation>
+ <translation>Memindah window agar tak menghalangi</translation>
</message>
<message>
<source>Puts a maximized window back to normal</source>
- <translation type="vanished">Mengembalikan yang termaksimumkan ke normal</translation>
+ <translation>Mengembalikan yang termaksimumkan ke normal</translation>
</message>
<message>
<source>Makes the window full screen</source>
- <translation type="vanished">Membuat window memenuhi layar</translation>
+ <translation>Membuat window memenuhi layar</translation>
</message>
<message>
<source>Closes the window</source>
- <translation type="vanished">Menutup window</translation>
+ <translation>Menutup window</translation>
</message>
<message>
<source>Holds the name of the window and contains controls to manipulate it</source>
- <translation type="vanished">Menampilkan nama window dan mewadahi kendali untuk memanipulasikannya</translation>
+ <translation>Menampilkan nama window dan mewadahi kendali untuk memanipulasikannya</translation>
</message>
</context>
<context>
<name>Q3ToolBar</name>
<message>
<source>More...</source>
- <translation type="vanished">Lebih...</translation>
+ <translation>Lebih...</translation>
</message>
</context>
<context>
<name>Q3UrlOperator</name>
<message>
<source>The protocol `%1' is not supported</source>
- <translation type="vanished">Protokol '%1' tak didukung</translation>
+ <translation>Protokol '%1' tak didukung</translation>
</message>
<message>
<source>The protocol `%1' does not support listing directories</source>
- <translation type="vanished">Protokol '%1' tak mendukung daftar direktori</translation>
+ <translation>Protokol '%1' tak mendukung daftar direktori</translation>
</message>
<message>
<source>The protocol `%1' does not support creating new directories</source>
- <translation type="vanished">Protokol '%1' tak mendukung pembuatan direktori baru</translation>
+ <translation>Protokol '%1' tak mendukung pembuatan direktori baru</translation>
</message>
<message>
<source>The protocol `%1' does not support removing files or directories</source>
- <translation type="vanished">Protokol '%1' tak mendukung penghapusan file atau direktori</translation>
+ <translation>Protokol '%1' tak mendukung penghapusan file atau direktori</translation>
</message>
<message>
<source>The protocol `%1' does not support renaming files or directories</source>
- <translation type="vanished">Protokol '%1' tak mendukung pengubahan nama file atau direktori</translation>
+ <translation>Protokol '%1' tak mendukung pengubahan nama file atau direktori</translation>
</message>
<message>
<source>The protocol `%1' does not support getting files</source>
- <translation type="vanished">Protokol '%1' tak mendukung pengambilan file</translation>
+ <translation>Protokol '%1' tak mendukung pengambilan file</translation>
</message>
<message>
<source>The protocol `%1' does not support putting files</source>
- <translation type="vanished">Protokol '%1' tak mendukung peletakan file</translation>
+ <translation>Protokol '%1' tak mendukung peletakan file</translation>
</message>
<message>
<source>The protocol `%1' does not support copying or moving files or directories</source>
- <translation type="vanished">Protokol '%1' tak mendukung penyalinan atau pemindahan file atau direktori</translation>
+ <translation>Protokol '%1' tak mendukung penyalinan atau pemindahan file atau direktori</translation>
</message>
<message>
<source>(unknown)</source>
- <translation type="vanished">(tak dikenal)</translation>
+ <translation>(tak dikenal)</translation>
</message>
</context>
<context>
<name>Q3Wizard</name>
<message>
<source>&Cancel</source>
- <translation type="vanished">&Batal</translation>
+ <translation>&Batal</translation>
</message>
<message>
<source>< &Back</source>
- <translation type="vanished">< Kem&bali</translation>
+ <translation>< Kem&bali</translation>
</message>
<message>
<source>&Next ></source>
- <translation type="vanished">La&njut ></translation>
+ <translation>La&njut ></translation>
</message>
<message>
<source>&Finish</source>
- <translation type="vanished">&Selesai</translation>
+ <translation>&Selesai</translation>
</message>
<message>
<source>&Help</source>
- <translation type="vanished">&Bantuan</translation>
+ <translation>&Bantuan</translation>
</message>
</context>
<context>
@@ -689,19 +689,19 @@ menjadi
</message>
<message>
<source>Operation on socket is not supported</source>
- <translation type="unfinished"></translation>
+ <translation>Operasi pada soket tidak didukung</translation>
</message>
<message>
<source>Connection timed out</source>
- <translation type="unfinished">Koneksi habis waktu</translation>
+ <translation>Koneksi habis waktu</translation>
</message>
<message>
<source>Trying to connect while connection is in progress</source>
- <translation type="unfinished"></translation>
+ <translation>Mencoba menyambung saat koneksi tengah berlangsung</translation>
</message>
<message>
<source>Network unreachable</source>
- <translation type="unfinished">Jaringan tak dapat dicapai</translation>
+ <translation>Jaringan tak dapat dicapai</translation>
</message>
</context>
<context>
@@ -723,15 +723,15 @@ menjadi
<name>QAccessibleActionInterface</name>
<message>
<source>Press</source>
- <translation type="unfinished">Tekan</translation>
+ <translation>Tekan</translation>
</message>
<message>
<source>Increase</source>
- <translation type="unfinished"></translation>
+ <translation>Naikkan</translation>
</message>
<message>
<source>Decrease</source>
- <translation type="unfinished"></translation>
+ <translation>Turunkan</translation>
</message>
<message>
<source>ShowMenu</source>
@@ -743,105 +743,105 @@ menjadi
</message>
<message>
<source>Toggle</source>
- <translation type="unfinished">Jungkitkan</translation>
+ <translation>Jungkitkan</translation>
</message>
<message>
<source>Scroll Left</source>
- <translation type="unfinished">Gulung Kiri</translation>
+ <translation>Gulung Kiri</translation>
</message>
<message>
<source>Scroll Right</source>
- <translation type="unfinished">Gulung Kanan</translation>
+ <translation>Gulung Kanan</translation>
</message>
<message>
<source>Scroll Up</source>
- <translation type="unfinished"></translation>
+ <translation>Gulung Atas</translation>
</message>
<message>
<source>Scroll Down</source>
- <translation type="unfinished"></translation>
+ <translation>Gulung Bawah</translation>
</message>
<message>
<source>Previous Page</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Sebelumnya</translation>
</message>
<message>
<source>Next Page</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Berikutnya</translation>
</message>
<message>
<source>Triggers the action</source>
- <translation type="unfinished"></translation>
+ <translation>Picu aksi</translation>
</message>
<message>
<source>Increase the value</source>
- <translation type="unfinished"></translation>
+ <translation>Naikkan nilai</translation>
</message>
<message>
<source>Decrease the value</source>
- <translation type="unfinished"></translation>
+ <translation>Turunkan nilai</translation>
</message>
<message>
<source>Shows the menu</source>
- <translation type="unfinished"></translation>
+ <translation>Tampilkan menu</translation>
</message>
<message>
<source>Sets the focus</source>
- <translation type="unfinished"></translation>
+ <translation>Menata fokus</translation>
</message>
<message>
<source>Toggles the state</source>
- <translation type="unfinished"></translation>
+ <translation>Menjungkitkan keadaan</translation>
</message>
<message>
<source>Scrolls to the left</source>
- <translation type="unfinished"></translation>
+ <translation>Menggulung ke kiri</translation>
</message>
<message>
<source>Scrolls to the right</source>
- <translation type="unfinished"></translation>
+ <translation>Menggulung ke kanan</translation>
</message>
<message>
<source>Scrolls up</source>
- <translation type="unfinished"></translation>
+ <translation>Menggulung ke atas</translation>
</message>
<message>
<source>Scrolls down</source>
- <translation type="unfinished"></translation>
+ <translation>Menggulung ke bawah</translation>
</message>
<message>
<source>Goes back a page</source>
- <translation type="unfinished"></translation>
+ <translation>Mundur satu halaman</translation>
</message>
<message>
<source>Goes to the next page</source>
- <translation type="unfinished"></translation>
+ <translation>Menuju ke halaman selanjutnya</translation>
</message>
</context>
<context>
<name>QAndroidPlatformTheme</name>
<message>
<source>Yes</source>
- <translation type="unfinished">Ya</translation>
+ <translation>Ya</translation>
</message>
<message>
<source>Yes to All</source>
- <translation type="unfinished"></translation>
+ <translation>Ya untuk Semua</translation>
</message>
<message>
<source>No</source>
- <translation type="unfinished">Tidak</translation>
+ <translation>Tidak</translation>
</message>
<message>
<source>No to All</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak untuk Semua</translation>
</message>
</context>
<context>
<name>QApplication</name>
<message>
<source>Activate</source>
- <translation type="vanished">Aktifkan</translation>
+ <translation>Aktifkan</translation>
</message>
<message>
<source>Executable '%1' requires Qt %2, found Qt %3.</source>
@@ -854,88 +854,88 @@ menjadi
<message>
<source>QT_LAYOUT_DIRECTION</source>
<comment>Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout.</comment>
- <translation type="vanished">LTR</translation>
+ <translation>LTR</translation>
</message>
<message>
<source>Activates the program's main window</source>
- <translation type="vanished">Aktifkan window utama program</translation>
+ <translation>Aktifkan window utama program</translation>
</message>
</context>
<context>
<name>QCheckBox</name>
<message>
<source>Uncheck</source>
- <translation type="vanished">Hapus contreng</translation>
+ <translation>Hapus contreng</translation>
</message>
<message>
<source>Check</source>
- <translation type="vanished">Contreng</translation>
+ <translation>Contreng</translation>
</message>
<message>
<source>Toggle</source>
- <translation type="vanished">Jungkitkan</translation>
+ <translation>Jungkitkan</translation>
</message>
</context>
<context>
<name>QCocoaMenuItem</name>
<message>
<source>About Qt</source>
- <translation type="unfinished">Tentang Qt</translation>
+ <translation>Tentang Qt</translation>
</message>
<message>
<source>About</source>
- <translation type="unfinished"></translation>
+ <translation>Tentang</translation>
</message>
<message>
<source>Config</source>
- <translation type="unfinished"></translation>
+ <translation>Konfig</translation>
</message>
<message>
<source>Preference</source>
- <translation type="unfinished"></translation>
+ <translation>Preferensi</translation>
</message>
<message>
<source>Options</source>
- <translation type="unfinished">Opsi</translation>
+ <translation>Opsi</translation>
</message>
<message>
<source>Setting</source>
- <translation type="unfinished"></translation>
+ <translation>Setelan</translation>
</message>
<message>
<source>Setup</source>
- <translation type="unfinished"></translation>
+ <translation>Penyiapan</translation>
</message>
<message>
<source>Quit</source>
- <translation type="unfinished">Keluar</translation>
+ <translation>Keluar</translation>
</message>
<message>
<source>Exit</source>
- <translation type="unfinished"></translation>
+ <translation>Keluar</translation>
</message>
<message>
<source>Cut</source>
- <translation type="unfinished">Potong</translation>
+ <translation>Potong</translation>
</message>
<message>
<source>Copy</source>
- <translation type="unfinished">Salin</translation>
+ <translation>Salin</translation>
</message>
<message>
<source>Paste</source>
- <translation type="unfinished">Tempel</translation>
+ <translation>Tempel</translation>
</message>
<message>
<source>Select All</source>
- <translation type="unfinished">Pilih Semua</translation>
+ <translation>Pilih Semua</translation>
</message>
</context>
<context>
<name>QCocoaTheme</name>
<message>
<source>Don't Save</source>
- <translation type="unfinished">Jangan Simpan</translation>
+ <translation>Jangan Simpan</translation>
</message>
</context>
<context>
@@ -982,31 +982,32 @@ menjadi
</message>
<message>
<source>Select color</source>
- <translation type="vanished">Pilih warna</translation>
+ <translation>Pilih warna</translation>
</message>
<message>
<source>&HTML:</source>
- <translation type="unfinished"></translation>
+ <translation>&HTML:</translation>
</message>
<message>
<source>Cursor at %1, %2
Press ESC to cancel</source>
- <translation type="unfinished"></translation>
+ <translation>Kursor di %1, %2
+Tekan ESC untuk membatalkan</translation>
</message>
<message>
<source>Select Color</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih Warna</translation>
</message>
<message>
<source>&Pick Screen Color</source>
- <translation type="unfinished"></translation>
+ <translation>&Pilih Warna Layar</translation>
</message>
</context>
<context>
<name>QComboBox</name>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>False</source>
@@ -1018,54 +1019,54 @@ Press ESC to cancel</source>
</message>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Open the combo box selection popup</source>
- <translation type="unfinished"></translation>
+ <translation>Buka popup pemilihan kotak kombo</translation>
</message>
</context>
<context>
<name>QCommandLineParser</name>
<message>
<source>Displays version information.</source>
- <translation type="unfinished"></translation>
+ <translation>Tampilkan informasi versi.</translation>
</message>
<message>
<source>Displays this help.</source>
- <translation type="unfinished"></translation>
+ <translation>Tampilkan bantuan ini.</translation>
</message>
<message>
<source>Unknown option '%1'.</source>
- <translation type="unfinished"></translation>
+ <translation>Opsi '%1' tidak dikenal.</translation>
</message>
<message>
<source>Unknown options: %1.</source>
- <translation type="unfinished"></translation>
+ <translation>Opsi tidak dikenal: %1.</translation>
</message>
<message>
<source>Missing value after '%1'.</source>
- <translation type="unfinished"></translation>
+ <translation>Kurang nilai setelah '%1'.</translation>
</message>
<message>
<source>Unexpected value after '%1'.</source>
- <translation type="unfinished"></translation>
+ <translation>Nilai yang tidak diharapkan setelah '%1'.</translation>
</message>
<message>
<source>[options]</source>
- <translation type="unfinished"></translation>
+ <translation>[opsi]</translation>
</message>
<message>
<source>Usage: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Cara pakai: %1</translation>
</message>
<message>
<source>Options:</source>
- <translation type="unfinished"></translation>
+ <translation>Opsi:</translation>
</message>
<message>
<source>Arguments:</source>
- <translation type="unfinished"></translation>
+ <translation>Argumen:</translation>
</message>
</context>
<context>
@@ -1073,27 +1074,27 @@ Press ESC to cancel</source>
<message>
<source>%1: permission denied</source>
<comment>QSystemSemaphore</comment>
- <translation type="vanished">%1: ijin ditolak</translation>
+ <translation>%1: ijin ditolak</translation>
</message>
<message>
<source>%1: already exists</source>
<comment>QSystemSemaphore</comment>
- <translation type="vanished">%1: telah ada</translation>
+ <translation>%1: telah ada</translation>
</message>
<message>
<source>%1: doesn't exists</source>
<comment>QSystemSemaphore</comment>
- <translation type="vanished">%1: tidak ada</translation>
+ <translation>%1: tidak ada</translation>
</message>
<message>
<source>%1: out of resources</source>
<comment>QSystemSemaphore</comment>
- <translation type="vanished">%1: kehabisan sumber daya</translation>
+ <translation>%1: kehabisan sumber daya</translation>
</message>
<message>
<source>%1: unknown error %2</source>
<comment>QSystemSemaphore</comment>
- <translation type="vanished">%1: kesalahan tak dikenal %2</translation>
+ <translation>%1: kesalahan tak dikenal %2</translation>
</message>
<message>
<source>%1: key is empty</source>
@@ -1115,79 +1116,79 @@ Press ESC to cancel</source>
<name>QCupsJobWidget</name>
<message>
<source>Job</source>
- <translation type="unfinished"></translation>
+ <translation>Tugas</translation>
</message>
<message>
<source>Job Control</source>
- <translation type="unfinished"></translation>
+ <translation>Kendali Tugas</translation>
</message>
<message>
<source>Scheduled printing:</source>
- <translation type="unfinished"></translation>
+ <translation>Pencetakan terjadwal:</translation>
</message>
<message>
<source>Billing information:</source>
- <translation type="unfinished"></translation>
+ <translation>Informasi tagihan:</translation>
</message>
<message>
<source>Job priority:</source>
- <translation type="unfinished"></translation>
+ <translation>Prioritas tugas:</translation>
</message>
<message>
<source>Banner Pages</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Banner</translation>
</message>
<message>
<source>End:</source>
<comment>Banner page at end</comment>
- <translation type="unfinished"></translation>
+ <translation>Akhir:</translation>
</message>
<message>
<source>Start:</source>
<comment>Banner page at start</comment>
- <translation type="unfinished"></translation>
+ <translation>Awal:</translation>
</message>
<message>
<source>Print Immediately</source>
- <translation type="unfinished"></translation>
+ <translation>Cetak Sekarang Juga</translation>
</message>
<message>
<source>Hold Indefinitely</source>
- <translation type="unfinished"></translation>
+ <translation>Tahan Selamanya</translation>
</message>
<message>
<source>Day (06:00 to 17:59)</source>
- <translation type="unfinished"></translation>
+ <translation>Siang (06:00 sampai 17:59)</translation>
</message>
<message>
<source>Night (18:00 to 05:59)</source>
- <translation type="unfinished"></translation>
+ <translation>Malam (18:00 sampai 05:59)</translation>
</message>
<message>
<source>Second Shift (16:00 to 23:59)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Shift Ke Dua (16:00 sampai 23:59)</translation>
</message>
<message>
<source>Third Shift (00:00 to 07:59)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Shift Ke Tiga (00:00 sampai 07:59)</translation>
</message>
<message>
<source>Weekend (Saturday to Sunday)</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Akhir Pekan (Sabtu sampai Minggu)</translation>
</message>
<message>
<source>Specific Time</source>
- <translation type="unfinished"></translation>
+ <translation>Waktu Tertentu</translation>
</message>
<message>
<source>None</source>
<comment>CUPS Banner page</comment>
- <translation type="unfinished">Nihil</translation>
+ <translation>Nihil</translation>
</message>
<message>
<source>Standard</source>
<comment>CUPS Banner page</comment>
- <translation type="unfinished"></translation>
+ <translation>Standar</translation>
</message>
<message>
<source>Unclassified</source>
@@ -1197,7 +1198,7 @@ Press ESC to cancel</source>
<message>
<source>Confidential</source>
<comment>CUPS Banner page</comment>
- <translation type="unfinished"></translation>
+ <translation>Konfidensial</translation>
</message>
<message>
<source>Classified</source>
@@ -1207,12 +1208,12 @@ Press ESC to cancel</source>
<message>
<source>Secret</source>
<comment>CUPS Banner page</comment>
- <translation type="unfinished"></translation>
+ <translation>Rahasia</translation>
</message>
<message>
<source>Top Secret</source>
<comment>CUPS Banner page</comment>
- <translation type="unfinished"></translation>
+ <translation>Sangat Rahasia</translation>
</message>
</context>
<context>
@@ -1265,60 +1266,60 @@ Press ESC to cancel</source>
<name>QDBusTrayIcon</name>
<message>
<source>OK</source>
- <translation type="unfinished">OK</translation>
+ <translation>OK</translation>
</message>
</context>
<context>
<name>QDateTimeEdit</name>
<message>
<source>AM</source>
- <translation type="vanished">AM</translation>
+ <translation>AM</translation>
</message>
<message>
<source>am</source>
- <translation type="vanished">am</translation>
+ <translation>am</translation>
</message>
<message>
<source>PM</source>
- <translation type="vanished">PM</translation>
+ <translation>PM</translation>
</message>
<message>
<source>pm</source>
- <translation type="vanished">pm</translation>
+ <translation>pm</translation>
</message>
</context>
<context>
<name>QDateTimeParser</name>
<message>
<source>AM</source>
- <translation type="unfinished">AM</translation>
+ <translation>AM</translation>
</message>
<message>
<source>am</source>
- <translation type="unfinished">am</translation>
+ <translation>am</translation>
</message>
<message>
<source>PM</source>
- <translation type="unfinished">PM</translation>
+ <translation>PM</translation>
</message>
<message>
<source>pm</source>
- <translation type="unfinished">pm</translation>
+ <translation>pm</translation>
</message>
</context>
<context>
<name>QDial</name>
<message>
<source>QDial</source>
- <translation type="vanished">QDial</translation>
+ <translation>QDial</translation>
</message>
<message>
<source>SpeedoMeter</source>
- <translation type="vanished">SpeedoMeter</translation>
+ <translation>SpeedoMeter</translation>
</message>
<message>
<source>SliderHandle</source>
- <translation type="vanished">SliderHandle</translation>
+ <translation>SliderHandle</translation>
</message>
</context>
<context>
@@ -1329,7 +1330,7 @@ Press ESC to cancel</source>
</message>
<message>
<source>Done</source>
- <translation type="vanished">Selesai</translation>
+ <translation>Selesai</translation>
</message>
</context>
<context>
@@ -1340,83 +1341,83 @@ Press ESC to cancel</source>
</message>
<message>
<source>Save</source>
- <translation type="vanished">Simpan</translation>
+ <translation>Simpan</translation>
</message>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>Cancel</source>
- <translation type="vanished">Batal</translation>
+ <translation>Batal</translation>
</message>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Apply</source>
- <translation type="vanished">Terapkan</translation>
+ <translation>Terapkan</translation>
</message>
<message>
<source>Reset</source>
- <translation type="vanished">Reset</translation>
+ <translation>Reset</translation>
</message>
<message>
<source>Help</source>
- <translation type="vanished">Bantuan</translation>
+ <translation>Bantuan</translation>
</message>
<message>
<source>Don't Save</source>
- <translation type="vanished">Jangan Simpan</translation>
+ <translation>Jangan Simpan</translation>
</message>
<message>
<source>Discard</source>
- <translation type="vanished">Buang</translation>
+ <translation>Buang</translation>
</message>
<message>
<source>&Yes</source>
- <translation type="vanished">&Ya</translation>
+ <translation>&Ya</translation>
</message>
<message>
<source>Yes to &All</source>
- <translation type="vanished">Ya untuk Semu&a</translation>
+ <translation>Ya untuk Semu&a</translation>
</message>
<message>
<source>&No</source>
- <translation type="vanished">&Tidak</translation>
+ <translation>&Tidak</translation>
</message>
<message>
<source>N&o to All</source>
- <translation type="vanished">T&idak untuk Semua</translation>
+ <translation>T&idak untuk Semua</translation>
</message>
<message>
<source>Save All</source>
- <translation type="vanished">Simpan Semua</translation>
+ <translation>Simpan Semua</translation>
</message>
<message>
<source>Abort</source>
- <translation type="vanished">Gugurkan</translation>
+ <translation>Gugurkan</translation>
</message>
<message>
<source>Retry</source>
- <translation type="vanished">Coba Lagi</translation>
+ <translation>Coba Lagi</translation>
</message>
<message>
<source>Ignore</source>
- <translation type="vanished">Abaikan</translation>
+ <translation>Abaikan</translation>
</message>
<message>
<source>Restore Defaults</source>
- <translation type="vanished">Kembalikan Bawaan</translation>
+ <translation>Kembalikan Bawaan</translation>
</message>
<message>
<source>Close without Saving</source>
- <translation type="vanished">Tutup tanpa Menyimpan</translation>
+ <translation>Tutup tanpa Menyimpan</translation>
</message>
<message>
<source>&OK</source>
- <translation type="vanished">&OK</translation>
+ <translation>&OK</translation>
</message>
</context>
<context>
@@ -1448,106 +1449,106 @@ Press ESC to cancel</source>
<name>QDnsLookup</name>
<message>
<source>Operation cancelled</source>
- <translation type="unfinished"></translation>
+ <translation>Operasi dibatalkan</translation>
</message>
</context>
<context>
<name>QDnsLookupRunnable</name>
<message>
<source>IPv6 addresses for nameservers are currently not supported</source>
- <translation type="unfinished"></translation>
+ <translation>Alamat IPv6 untuk server DNS saat ini tidak didukung</translation>
</message>
<message>
<source>Invalid domain name</source>
- <translation type="unfinished"></translation>
+ <translation>Nama domain tidak valid</translation>
</message>
<message>
<source>Not yet supported on Android</source>
- <translation type="unfinished"></translation>
+ <translation>Belum didukung pada Android</translation>
</message>
<message>
<source>Resolver functions not found</source>
- <translation type="unfinished"></translation>
+ <translation>Fungsi resolver tidak ditemukan</translation>
</message>
<message>
<source>Resolver initialization failed</source>
- <translation type="unfinished"></translation>
+ <translation>Inisialisasi resolver gagal</translation>
</message>
<message>
<source>Server could not process query</source>
- <translation type="unfinished"></translation>
+ <translation>Server tidak bisa memroses kueri</translation>
</message>
<message>
<source>Server failure</source>
- <translation type="unfinished"></translation>
+ <translation>Kegagalan server</translation>
</message>
<message>
<source>Non existent domain</source>
- <translation type="unfinished"></translation>
+ <translation>Domain tidak ada</translation>
</message>
<message>
<source>Server refused to answer</source>
- <translation type="unfinished"></translation>
+ <translation>Server menolak menjawab</translation>
</message>
<message>
<source>Invalid reply received</source>
- <translation type="unfinished"></translation>
+ <translation>Jawaban yang diterima tidak valid</translation>
</message>
<message>
<source>Could not expand domain name</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa mengekspansi nama domain</translation>
</message>
<message>
<source>Invalid IPv4 address record</source>
- <translation type="unfinished"></translation>
+ <translation>Record alamat IPv4 tidak valid</translation>
</message>
<message>
<source>Invalid IPv6 address record</source>
- <translation type="unfinished"></translation>
+ <translation>Record alamat IPv6 tidak valid</translation>
</message>
<message>
<source>Invalid canonical name record</source>
- <translation type="unfinished"></translation>
+ <translation>Record nama kanonik tidak valid</translation>
</message>
<message>
<source>Invalid name server record</source>
- <translation type="unfinished"></translation>
+ <translation>Record server DNS tidak valid</translation>
</message>
<message>
<source>Invalid pointer record</source>
- <translation type="unfinished"></translation>
+ <translation>Record pointer tidak valid</translation>
</message>
<message>
<source>Invalid mail exchange record</source>
- <translation type="unfinished"></translation>
+ <translation>Record mail exchange tidak valid</translation>
</message>
<message>
<source>Invalid service record</source>
- <translation type="unfinished"></translation>
+ <translation>Record layanan tidak valid</translation>
</message>
<message>
<source>Invalid text record</source>
- <translation type="unfinished"></translation>
+ <translation>Record teks tidak valid</translation>
</message>
<message>
<source>Resolver library can't be loaded: No runtime library loading support</source>
- <translation type="unfinished"></translation>
+ <translation>Pustaka resolver tak bisa dimuat: Tidak ada dukungan pemuatan pustaka saat runtime</translation>
</message>
<message>
<source>No hostname given</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ada nama host yang diberikan</translation>
</message>
<message>
<source>Invalid hostname</source>
- <translation type="unfinished"></translation>
+ <translation>Nama host tidak valid</translation>
</message>
<message>
<source>Host %1 could not be found.</source>
- <translation type="unfinished"></translation>
+ <translation>Host %1 tidak dapat ditemukan.</translation>
</message>
<message>
<source>Unknown error</source>
- <translation type="unfinished">Kesalahan tak dikenal</translation>
+ <translation>Kesalahan tak dikenal</translation>
</message>
</context>
<context>
@@ -1559,7 +1560,7 @@ Press ESC to cancel</source>
</message>
<message>
<source>Dock</source>
- <translation type="vanished">Dok</translation>
+ <translation>Dok</translation>
</message>
<message>
<source>Float</source>
@@ -1572,18 +1573,18 @@ Press ESC to cancel</source>
</message>
<message>
<source>Closes the dock widget</source>
- <translation type="unfinished"></translation>
+ <translation>Menutup widget dok</translation>
</message>
</context>
<context>
<name>QDoubleSpinBox</name>
<message>
<source>More</source>
- <translation type="vanished">Lebih</translation>
+ <translation>Lebih</translation>
</message>
<message>
<source>Less</source>
- <translation type="vanished">Kurang</translation>
+ <translation>Kurang</translation>
</message>
</context>
<context>
@@ -1613,54 +1614,54 @@ Press ESC to cancel</source>
<name>QFile</name>
<message>
<source>Destination file is the same file.</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas tujuan adalah berkas yang sama.</translation>
</message>
<message>
<source>Source file does not exist.</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas sumber tidak ada.</translation>
</message>
<message>
<source>Destination file exists</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas tujuan sudah ada</translation>
</message>
<message>
<source>Error while renaming.</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat mengubah nama.</translation>
</message>
<message>
<source>Unable to restore from %1: %2</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa memulihkan dari %1: %2</translation>
</message>
<message>
<source>Will not rename sequential file using block copy</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak akan mengubah nama berkas sekuensial memakai penyalinan blok</translation>
</message>
<message>
<source>Cannot remove source file</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa menghapus berkas sumber</translation>
</message>
<message>
<source>Cannot open %1 for input</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membuka %1 untuk masukan</translation>
</message>
<message>
<source>Cannot open for output</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membuka untuk keluaran</translation>
</message>
<message>
<source>Failure to write block</source>
- <translation type="unfinished"></translation>
+ <translation>Kegagalan menulis blok</translation>
</message>
<message>
<source>Cannot create %1 for output</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membuat %1 untuk keluaran</translation>
</message>
</context>
<context>
<name>QFileDevice</name>
<message>
<source>No file engine available or engine does not support UnMapExtension</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ada mesin berkas yang tersedia atau mesin tidak mendukung UnMapExtension</translation>
</message>
</context>
<context>
@@ -1755,7 +1756,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Are sure you want to delete '%1'?</source>
- <translation type="vanished">Anda yakin hendak menghapus '%1'?</translation>
+ <translation>Anda yakin hendak menghapus '%1'?</translation>
</message>
<message>
<source>Could not delete directory.</source>
@@ -1819,63 +1820,63 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Go back</source>
- <translation type="unfinished"></translation>
+ <translation>Mundur</translation>
</message>
<message>
<source>Alt+Left</source>
- <translation type="unfinished"></translation>
+ <translation>Alt+Kiri</translation>
</message>
<message>
<source>Go forward</source>
- <translation type="unfinished"></translation>
+ <translation>Maju</translation>
</message>
<message>
<source>Alt+Right</source>
- <translation type="unfinished"></translation>
+ <translation>Alt+Kanan</translation>
</message>
<message>
<source>Go to the parent directory</source>
- <translation type="unfinished"></translation>
+ <translation>Ke direktori induk</translation>
</message>
<message>
<source>Alt+Up</source>
- <translation type="unfinished"></translation>
+ <translation>Alt+Naik</translation>
</message>
<message>
<source>Create a New Folder</source>
- <translation type="unfinished"></translation>
+ <translation>Buat Folder Baru</translation>
</message>
<message>
<source>Change to list view mode</source>
- <translation type="unfinished"></translation>
+ <translation>Ubah ke mode tilikan daftar</translation>
</message>
<message>
<source>Change to detail view mode</source>
- <translation type="unfinished"></translation>
+ <translation>Ubah ke mode tilikan rinci</translation>
</message>
<message>
<source>Sidebar</source>
- <translation type="unfinished"></translation>
+ <translation>Bilah sisi</translation>
</message>
<message>
<source>List of places and bookmarks</source>
- <translation type="unfinished"></translation>
+ <translation>Daftar tempat dan markah</translation>
</message>
<message>
<source>Files</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas</translation>
</message>
<message>
<source>All files (*)</source>
- <translation type="unfinished"></translation>
+ <translation>Semua berkas (*.*)</translation>
</message>
<message>
<source>Delete</source>
- <translation type="unfinished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
<message>
<source>Are you sure you want to delete '%1'?</source>
- <translation type="unfinished"></translation>
+ <translation>Anda yakin hendak menghapus '%1'?</translation>
</message>
<message>
<source>Recent Places</source>
@@ -1884,27 +1885,27 @@ Anda tetap ingin menghapusnya?</translation>
<message>
<source>%1 File</source>
<extracomment>%1 is a file name suffix, for example txt</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Berkas %1</translation>
</message>
<message>
<source>File Folder</source>
<comment>Match Windows Explorer</comment>
- <translation type="unfinished"></translation>
+ <translation>Folder Berkas</translation>
</message>
<message>
<source>Folder</source>
<comment>All other platforms</comment>
- <translation type="unfinished"></translation>
+ <translation>Folder</translation>
</message>
<message>
<source>Alias</source>
<comment>OS X Finder</comment>
- <translation type="unfinished"></translation>
+ <translation>Alias</translation>
</message>
<message>
<source>Shortcut</source>
<comment>All other platforms</comment>
- <translation type="unfinished"></translation>
+ <translation>Pintasan</translation>
</message>
</context>
<context>
@@ -1969,14 +1970,14 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>%1 byte(s)</source>
- <translation type="unfinished"></translation>
+ <translation>%1 byte</translation>
</message>
</context>
<context>
<name>QFontDatabase</name>
<message>
<source>Normal</source>
- <translation type="vanished">Normal</translation>
+ <translation>Normal</translation>
</message>
<message>
<source>Bold</source>
@@ -2142,33 +2143,33 @@ Anda tetap ingin menghapusnya?</translation>
<message>
<source>Normal</source>
<comment>The Normal or Regular font weight</comment>
- <translation type="unfinished">Normal</translation>
+ <translation>Normal</translation>
</message>
<message>
<source>Medium</source>
<comment>The Medium font weight</comment>
- <translation type="unfinished"></translation>
+ <translation>Sedang</translation>
</message>
<message>
<source>Thin</source>
- <translation type="unfinished"></translation>
+ <translation>Tipis</translation>
</message>
<message>
<source>Extra Light</source>
- <translation type="unfinished"></translation>
+ <translation>Ekstra Ringan</translation>
</message>
<message>
<source>Extra Bold</source>
- <translation type="unfinished"></translation>
+ <translation>Ekstra Tebal</translation>
</message>
<message>
<source>Extra</source>
<extracomment>The word for "Extra" as in "Extra Bold, Extra Thin" used as a pattern for string searches</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ekstra</translation>
</message>
<message>
<source>N'Ko</source>
- <translation type="unfinished"></translation>
+ <translation>N'Ko</translation>
</message>
</context>
<context>
@@ -2230,7 +2231,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Connection refused for data connection</source>
- <translation type="vanished">Sambungan ditolak untuk koneksi data</translation>
+ <translation>Sambungan ditolak untuk koneksi data</translation>
</message>
<message>
<source>Unknown error</source>
@@ -2295,50 +2296,50 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Host %1 found</source>
- <translation type="vanished">Host %1 ditemukan</translation>
+ <translation>Host %1 ditemukan</translation>
</message>
<message>
<source>Connection to %1 closed</source>
- <translation type="vanished">Sambungan ke %1 ditutup</translation>
+ <translation>Sambungan ke %1 ditutup</translation>
</message>
<message>
<source>Host found</source>
- <translation type="vanished">Host ditemukan</translation>
+ <translation>Host ditemukan</translation>
</message>
<message>
<source>Connected to host</source>
- <translation type="vanished">Tersambung ke host</translation>
+ <translation>Tersambung ke host</translation>
</message>
<message>
<source>Connection timed out to host %1</source>
- <translation type="unfinished"></translation>
+ <translation>Sambungan habis waktu ke host %1</translation>
</message>
<message>
<source>Data Connection refused</source>
- <translation type="unfinished"></translation>
+ <translation>Koneksi data ditolak</translation>
</message>
</context>
<context>
<name>QGnomeTheme</name>
<message>
<source>&OK</source>
- <translation type="unfinished">&OK</translation>
+ <translation>&OK</translation>
</message>
<message>
<source>&Save</source>
- <translation type="unfinished">&Simpan</translation>
+ <translation>&Simpan</translation>
</message>
<message>
<source>&Cancel</source>
- <translation type="unfinished">&Batal</translation>
+ <translation>&Batal</translation>
</message>
<message>
<source>&Close</source>
- <translation type="unfinished">Tutu&p</translation>
+ <translation>Tutu&p</translation>
</message>
<message>
<source>Close without Saving</source>
- <translation type="unfinished">Tutup tanpa Menyimpan</translation>
+ <translation>Tutup tanpa Menyimpan</translation>
</message>
</context>
<context>
@@ -2346,7 +2347,7 @@ Anda tetap ingin menghapusnya?</translation>
<message>
<source>QT_LAYOUT_DIRECTION</source>
<comment>Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout.</comment>
- <translation type="unfinished">LTR</translation>
+ <translation>LTR</translation>
</message>
</context>
<context>
@@ -2357,7 +2358,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>No host name given</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ada nama host yang diberikan</translation>
</message>
</context>
<context>
@@ -2376,38 +2377,38 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>No host name given</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ada nama host yang diberikan</translation>
</message>
<message>
<source>Invalid hostname</source>
- <translation type="unfinished"></translation>
+ <translation>Nama host tidak valid</translation>
</message>
<message>
<source>Unknown error (%1)</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan tak dikenal (%1)</translation>
</message>
</context>
<context>
<name>QHttp</name>
<message>
<source>Unknown error</source>
- <translation type="vanished">Kesalahan tak dikenal</translation>
+ <translation>Kesalahan tak dikenal</translation>
</message>
<message>
<source>Request aborted</source>
- <translation type="vanished">Permintaan digugurkan</translation>
+ <translation>Permintaan digugurkan</translation>
</message>
<message>
<source>No server set to connect to</source>
- <translation type="vanished">Server untuk dihubungi tak ditata</translation>
+ <translation>Server untuk dihubungi tak ditata</translation>
</message>
<message>
<source>Wrong content length</source>
- <translation type="vanished">Panjang isi salah</translation>
+ <translation>Panjang isi salah</translation>
</message>
<message>
<source>Server closed connection unexpectedly</source>
- <translation type="vanished">Server menutup koneksi tak terduga</translation>
+ <translation>Server menutup koneksi tak terduga</translation>
</message>
<message>
<source>Connection refused</source>
@@ -2419,35 +2420,35 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>HTTP request failed</source>
- <translation type="vanished">Permintaan HTTP gagal</translation>
+ <translation>Permintaan HTTP gagal</translation>
</message>
<message>
<source>Invalid HTTP response header</source>
- <translation type="vanished">Header respon HTTP tak valid</translation>
+ <translation>Header respon HTTP tak valid</translation>
</message>
<message>
<source>Invalid HTTP chunked body</source>
- <translation type="vanished">Body chunked HTTP tak valid</translation>
+ <translation>Body chunked HTTP tak valid</translation>
</message>
<message>
<source>Host %1 found</source>
- <translation type="vanished">Host %1 ditemukan</translation>
+ <translation>Host %1 ditemukan</translation>
</message>
<message>
<source>Connected to host %1</source>
- <translation type="vanished">Tersambung ke host %1</translation>
+ <translation>Tersambung ke host %1</translation>
</message>
<message>
<source>Connection to %1 closed</source>
- <translation type="vanished">Sambungan ke %1 ditutup</translation>
+ <translation>Sambungan ke %1 ditutup</translation>
</message>
<message>
<source>Host found</source>
- <translation type="vanished">Host ditemukan</translation>
+ <translation>Host ditemukan</translation>
</message>
<message>
<source>Connected to host</source>
- <translation type="vanished">Tersambung ke host</translation>
+ <translation>Tersambung ke host</translation>
</message>
<message>
<source>Connection closed</source>
@@ -2455,19 +2456,19 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Proxy authentication required</source>
- <translation type="vanished">Otentikasi proksi diperlukan</translation>
+ <translation>Otentikasi proksi diperlukan</translation>
</message>
<message>
<source>Authentication required</source>
- <translation type="vanished">Otentikasi diperlukan</translation>
+ <translation>Otentikasi diperlukan</translation>
</message>
<message>
<source>HTTPS connection requested but SSL support not compiled in</source>
- <translation type="vanished">Koneksi HTTPS diminta tapi dukungan SSL tak disertakan saat kompail</translation>
+ <translation>Koneksi HTTPS diminta tapi dukungan SSL tak disertakan saat kompail</translation>
</message>
<message>
<source>Connection refused (or timed out)</source>
- <translation type="vanished">Sambungan ditolak (atau habis waktu)</translation>
+ <translation>Sambungan ditolak (atau habis waktu)</translation>
</message>
<message>
<source>Proxy requires authentication</source>
@@ -2491,11 +2492,11 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Too many redirects</source>
- <translation type="unfinished"></translation>
+ <translation>Terlalu banyak pengalihan</translation>
</message>
<message>
<source>Insecure redirect</source>
- <translation type="unfinished"></translation>
+ <translation>Pengalihan tidak aman</translation>
</message>
</context>
<context>
@@ -2506,35 +2507,35 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Did not receive HTTP response from proxy</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak menerima respon HTTP dari proksi</translation>
</message>
<message>
<source>Error parsing authentication request from proxy</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat mengurai permintaan otentikasi dari proksi</translation>
</message>
<message>
<source>Proxy denied connection</source>
- <translation type="unfinished"></translation>
+ <translation>Proksi menolak koneksi</translation>
</message>
<message>
<source>Error communicating with HTTP proxy</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat berkomunikasi dengan proksi HTTP</translation>
</message>
<message>
<source>Proxy server not found</source>
- <translation type="unfinished"></translation>
+ <translation>Server proksi tidak ditemukan</translation>
</message>
<message>
<source>Proxy connection refused</source>
- <translation type="unfinished"></translation>
+ <translation>Koneksi proksi ditolak</translation>
</message>
<message>
<source>Proxy server connection timed out</source>
- <translation type="unfinished"></translation>
+ <translation>Koneksi server proksi habis waktu</translation>
</message>
<message>
<source>Proxy connection closed prematurely</source>
- <translation type="unfinished"></translation>
+ <translation>Koneksi proksi ditutup secara prematur</translation>
</message>
</context>
<context>
@@ -2651,177 +2652,177 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>file to open is a directory</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas yang akan dibuka adalah sebuah direktori</translation>
</message>
</context>
<context>
<name>QImageReader</name>
<message>
<source>Invalid device</source>
- <translation type="unfinished"></translation>
+ <translation>Peranti tidak valid</translation>
</message>
<message>
<source>File not found</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas tidak ditemukan</translation>
</message>
<message>
<source>Unsupported image format</source>
- <translation type="unfinished"></translation>
+ <translation>Format citra tidak didukung</translation>
</message>
<message>
<source>Unable to read image data</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membaca data citra</translation>
</message>
<message>
<source>Unknown error</source>
- <translation type="unfinished">Kesalahan tak dikenal</translation>
+ <translation>Kesalahan tak dikenal</translation>
</message>
</context>
<context>
<name>QImageWriter</name>
<message>
<source>Unknown error</source>
- <translation type="unfinished">Kesalahan tak dikenal</translation>
+ <translation>Kesalahan tak dikenal</translation>
</message>
<message>
<source>Device is not set</source>
- <translation type="unfinished"></translation>
+ <translation>Peranti tidak ditata</translation>
</message>
<message>
<source>Device not writable</source>
- <translation type="unfinished"></translation>
+ <translation>Peranti tidak dapat ditulisi</translation>
</message>
<message>
<source>Unsupported image format</source>
- <translation type="unfinished"></translation>
+ <translation>Format citra tidak didukung</translation>
</message>
</context>
<context>
<name>QInputContext</name>
<message>
<source>XIM</source>
- <translation type="vanished">XIM</translation>
+ <translation>XIM</translation>
</message>
<message>
<source>XIM input method</source>
- <translation type="vanished">Metoda masukan XIM</translation>
+ <translation>Metoda masukan XIM</translation>
</message>
<message>
<source>Windows input method</source>
- <translation type="vanished">Metoda masukan Windows</translation>
+ <translation>Metoda masukan Windows</translation>
</message>
<message>
<source>Mac OS X input method</source>
- <translation type="vanished">Metoda masuka Mac OS X</translation>
+ <translation>Metoda masuka Mac OS X</translation>
</message>
</context>
<context>
<name>QInputDialog</name>
<message>
<source>Enter a value:</source>
- <translation type="unfinished"></translation>
+ <translation>Masukkan suatu nilai:</translation>
</message>
</context>
<context>
<name>QJsonParseError</name>
<message>
<source>no error occurred</source>
- <translation type="unfinished">tak terjadi kesalahan</translation>
+ <translation>tak terjadi kesalahan</translation>
</message>
<message>
<source>unterminated object</source>
- <translation type="unfinished"></translation>
+ <translation>objek tak diterminasi</translation>
</message>
<message>
<source>missing name separator</source>
- <translation type="unfinished"></translation>
+ <translation>kurang pemisah nama</translation>
</message>
<message>
<source>unterminated array</source>
- <translation type="unfinished"></translation>
+ <translation>larik tak diterminasi</translation>
</message>
<message>
<source>missing value separator</source>
- <translation type="unfinished"></translation>
+ <translation>kurang pemisah nilai</translation>
</message>
<message>
<source>illegal value</source>
- <translation type="unfinished"></translation>
+ <translation>nilai tidak legal</translation>
</message>
<message>
<source>invalid termination by number</source>
- <translation type="unfinished"></translation>
+ <translation>terminasi dengan angka yang tidak valid</translation>
</message>
<message>
<source>illegal number</source>
- <translation type="unfinished"></translation>
+ <translation>angka tidak legal</translation>
</message>
<message>
<source>invalid escape sequence</source>
- <translation type="unfinished"></translation>
+ <translation>urutan escape yang tidak valid</translation>
</message>
<message>
<source>invalid UTF8 string</source>
- <translation type="unfinished"></translation>
+ <translation>string UTF8 yang tidak valid</translation>
</message>
<message>
<source>unterminated string</source>
- <translation type="unfinished"></translation>
+ <translation>string tidak diterminasi</translation>
</message>
<message>
<source>object is missing after a comma</source>
- <translation type="unfinished"></translation>
+ <translation>kurang objek setelah koma</translation>
</message>
<message>
<source>too deeply nested document</source>
- <translation type="unfinished"></translation>
+ <translation>dokumen bersarang terlalu dalam</translation>
</message>
<message>
<source>too large document</source>
- <translation type="unfinished"></translation>
+ <translation>dokumen terlalu besar</translation>
</message>
<message>
<source>garbage at the end of the document</source>
- <translation type="unfinished"></translation>
+ <translation>sampah di ujung dokumen</translation>
</message>
</context>
<context>
<name>QKeySequenceEdit</name>
<message>
<source>Press shortcut</source>
- <translation type="unfinished"></translation>
+ <translation>Tekan pintasan</translation>
</message>
<message>
<source>%1, ...</source>
<extracomment>This text is an "unfinished" shortcut, expands like "Ctrl+A, ..."</extracomment>
- <translation type="unfinished"></translation>
+ <translation>%1, ...</translation>
</message>
</context>
<context>
<name>QLibrary</name>
<message>
<source>QLibrary::load_sys: Cannot load %1 (%2)</source>
- <translation type="vanished">QLibrary::load_sys: Tak bisa memuat %1 (%2)</translation>
+ <translation>QLibrary::load_sys: Tak bisa memuat %1 (%2)</translation>
</message>
<message>
<source>QLibrary::unload_sys: Cannot unload %1 (%2)</source>
- <translation type="vanished">QLibrary::unload_sys: Tak bisa membongkar %1 (%2)</translation>
+ <translation>QLibrary::unload_sys: Tak bisa membongkar %1 (%2)</translation>
</message>
<message>
<source>QLibrary::resolve_sys: Symbol "%1" undefined in %2 (%3)</source>
- <translation type="vanished">QLibrary::resolve_sys: Simbol "%1" tak terdefinisi dalam %2 (%3)</translation>
+ <translation>QLibrary::resolve_sys: Simbol "%1" tak terdefinisi dalam %2 (%3)</translation>
</message>
<message>
<source>Could not mmap '%1': %2</source>
- <translation type="vanished">Tak bisa mmap '%1': %2</translation>
+ <translation>Tak bisa mmap '%1': %2</translation>
</message>
<message>
<source>Plugin verification data mismatch in '%1'</source>
- <translation type="vanished">Data verifikasi plugin tak cocok dalam '%1'</translation>
+ <translation>Data verifikasi plugin tak cocok dalam '%1'</translation>
</message>
<message>
<source>Could not unmap '%1': %2</source>
- <translation type="vanished">Tak bisa unmap '%1': %2</translation>
+ <translation>Tak bisa unmap '%1': %2</translation>
</message>
<message>
<source>The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]</source>
@@ -2829,7 +2830,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3"</source>
- <translation type="vanished">Plugin '%1' memakai pustaka Qt yang tak kompatibel. Mengharapkan kunci build "%2", mendapat "%3"</translation>
+ <translation>Plugin '%1' memakai pustaka Qt yang tak kompatibel. Mengharapkan kunci build "%2", mendapat "%3"</translation>
</message>
<message>
<source>Unknown error</source>
@@ -2849,63 +2850,63 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>'%1' is not an ELF object (%2)</source>
- <translation type="unfinished"></translation>
+ <translation>'%1' bukan suatu objek ELF (%2)</translation>
</message>
<message>
<source>'%1' is not an ELF object</source>
- <translation type="unfinished"></translation>
+ <translation>'%1' bukan suatu objek ELF</translation>
</message>
<message>
<source>'%1' is an invalid ELF object (%2)</source>
- <translation type="unfinished"></translation>
+ <translation>'%1' bukan objek ELF yang valid (%2)</translation>
</message>
<message>
<source>Failed to extract plugin meta data from '%1'</source>
- <translation type="unfinished"></translation>
+ <translation>Gagal mengekstrak meta data plugin dari '%1'</translation>
</message>
<message>
<source>Cannot load library %1: %2</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa memuat pustaka %1: %2</translation>
</message>
<message>
<source>Cannot unload library %1: %2</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa membongkar muat pustaka %1: %2</translation>
</message>
<message>
<source>Cannot resolve symbol "%1" in %2: %3</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa mengurai simbol "%1" dalam %2: %3</translation>
</message>
<message>
<source>'%1' is not a valid Mach-O binary (%2)</source>
- <translation type="unfinished"></translation>
+ <translation>'%1' bukan biner Mach-O yang valid (%2)</translation>
</message>
<message>
<source>file is corrupt</source>
- <translation type="unfinished"></translation>
+ <translation>berkas terkorupsi</translation>
</message>
<message>
<source>file too small</source>
- <translation type="unfinished"></translation>
+ <translation>berkas terlalu kecil</translation>
</message>
<message>
<source>no suitable architecture in fat binary</source>
- <translation type="unfinished"></translation>
+ <translation>tak ada arsitektur yang cocok dalam biner fat</translation>
</message>
<message>
<source>invalid magic %1</source>
- <translation type="unfinished"></translation>
+ <translation>magic %1 tak valid</translation>
</message>
<message>
<source>wrong architecture</source>
- <translation type="unfinished"></translation>
+ <translation>salah arsitektur</translation>
</message>
<message>
<source>not a dynamic library</source>
- <translation type="unfinished"></translation>
+ <translation>bukan suatu pustaka dinamis</translation>
</message>
<message>
<source>'%1' is not a Qt plugin</source>
- <translation type="unfinished"></translation>
+ <translation>'%1' bukanlah suatu plugin Qt</translation>
</message>
</context>
<context>
@@ -3002,26 +3003,26 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>%1: Operation not permitted when socket is in this state</source>
- <translation type="unfinished"></translation>
+ <translation>%1: Operasi tak diizinkan ketika soket dalam keadaan ini</translation>
</message>
<message>
<source>%1: Unknown error</source>
- <translation type="unfinished"></translation>
+ <translation>%1: Kesalahan tak dikenal</translation>
</message>
<message>
<source>Trying to connect while connection is in progress</source>
- <translation type="unfinished"></translation>
+ <translation>Mencoba menyambung saat koneksi tengah berlangsung</translation>
</message>
<message>
<source>%1: Access denied</source>
- <translation type="unfinished"></translation>
+ <translation>%1: Akses ditolak</translation>
</message>
</context>
<context>
<name>QMYSQLDriver</name>
<message>
<source>Unable to open database '</source>
- <translation type="vanished">Tak bisa membuka database '</translation>
+ <translation>Tak bisa membuka database '</translation>
</message>
<message>
<source>Unable to connect</source>
@@ -3041,11 +3042,12 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Unable to allocate a MYSQL object</source>
- <translation type="unfinished"></translation>
+ <translatorcomment>Tak bisa mengalokasikan sebuah objek MySQL</translatorcomment>
+ <translation></translation>
</message>
<message>
<source>Unable to open database '%1'</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa membuka database '%1'</translation>
</message>
</context>
<context>
@@ -3181,15 +3183,15 @@ Anda tetap ingin menghapusnya?</translation>
<name>QMenu</name>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>Execute</source>
- <translation type="vanished">Jalankan</translation>
+ <translation>Jalankan</translation>
</message>
</context>
<context>
@@ -3208,7 +3210,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source><p>This program uses Qt version %1.</p></source>
- <translation type="vanished"><p>Program ini memakai Qt versi %1.</p></translation>
+ <translation><p>Program ini memakai Qt versi %1.</p></translation>
</message>
<message>
<source>Show Details...</source>
@@ -3220,15 +3222,15 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source><p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <a href="http://www.trolltech.com/company/model/">www.trolltech.com/company/model/</a> for an overview of Qt licensing.</p></source>
- <translation type="vanished"><p>Program ini memakai Qt Open Source Edition versi %1.</p><p>Qt Open Source Edition ditujukan bagi pengembangan aplikasi Open Source. Anda perlu lisensi komersial Qt bagi pengembangan aplikasi proprietary (closed source).</p><p>Silakan lihat <a href="http://www.trolltech.com/company/model/">www.trolltech.com/company/model/</a> untuk ringkasan tentang masalah lisensi Qt.</p></translation>
+ <translation><p>Program ini memakai Qt Open Source Edition versi %1.</p><p>Qt Open Source Edition ditujukan bagi pengembangan aplikasi Open Source. Anda perlu lisensi komersial Qt bagi pengembangan aplikasi proprietary (closed source).</p><p>Silakan lihat <a href="http://www.trolltech.com/company/model/">www.trolltech.com/company/model/</a> untuk ringkasan tentang masalah lisensi Qt.</p></translation>
</message>
<message>
<source><h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS Windows, Mac OS X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is a Nokia product. See <a href="http://www.trolltech.com/qt/">www.trolltech.com/qt/&l [...]
- <translation type="vanished"><h3>Tentang Qt</h3>%1<p>Qt adalah toolkit C++ untuk pengembangan aplikasi lintas platform.</p><p>Qt menyediakan portabilitas sumber tunggal mencakup MS Windows, Mac OS X, Linux, dan semua varian Unix komersial utama. Qt juga tersedia bagi device embedded sebagai Qt for Embedded Linux dan Qt for Windows CE.</p><p>Qt adalah sebuah produk Nokia. Lihat <a href="http://www.trollte [...]
+ <translation><h3>Tentang Qt</h3>%1<p>Qt adalah toolkit C++ untuk pengembangan aplikasi lintas platform.</p><p>Qt menyediakan portabilitas sumber tunggal mencakup MS Windows, Mac OS X, Linux, dan semua varian Unix komersial utama. Qt juga tersedia bagi device embedded sebagai Qt for Embedded Linux dan Qt for Windows CE.</p><p>Qt adalah sebuah produk Nokia. Lihat <a href="http://www.trolltech.com/qt/" [...]
</message>
<message>
<source><h3>About Qt</h3><p>This program uses Qt version %1.</p></source>
- <translation type="unfinished"></translation>
+ <translation><h3>Tentang Qt</h3><p>Program ini memakai Qt versi %1.</p></translation>
</message>
<message>
<source><p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across all major desktop operating systems. It is also available for embedded Linux and other embedded and mobile operating systems.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p><p>Qt licensed under our commercial license agreement is appropriate [...]
@@ -3239,18 +3241,18 @@ Anda tetap ingin menghapusnya?</translation>
<name>QMultiInputContext</name>
<message>
<source>Select IM</source>
- <translation type="vanished">Pilih IM</translation>
+ <translation>Pilih IM</translation>
</message>
</context>
<context>
<name>QMultiInputContextPlugin</name>
<message>
<source>Multiple input method switcher</source>
- <translation type="vanished">Penukar metoda masukan berganda</translation>
+ <translation>Penukar metoda masukan berganda</translation>
</message>
<message>
<source>Multiple input method switcher that uses the context menu of the text widgets</source>
- <translation type="vanished">Penukar metoda masukan berganda yang memakai menu konteks dari widget teks</translation>
+ <translation>Penukar metoda masukan berganda yang memakai menu konteks dari widget teks</translation>
</message>
</context>
<context>
@@ -3361,44 +3363,44 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Temporary error</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan sementara</translation>
</message>
<message>
<source>Network dropped connection on reset</source>
- <translation type="unfinished"></translation>
+ <translation>Jaringan memutus koneksi saat reset</translation>
</message>
<message>
<source>Connection reset by peer</source>
- <translation type="unfinished"></translation>
+ <translation>Koneksi direset oleh peer</translation>
</message>
</context>
<context>
<name>QNetworkAccessCacheBackend</name>
<message>
<source>Error opening %1</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat membuka %1</translation>
</message>
</context>
<context>
<name>QNetworkAccessDataBackend</name>
<message>
<source>Invalid URI: %1</source>
- <translation type="unfinished">URI tak valid: %1</translation>
+ <translation>URI tak valid: %1</translation>
</message>
</context>
<context>
<name>QNetworkAccessDebugPipeBackend</name>
<message>
<source>Write error writing to %1: %2</source>
- <translation type="unfinished">Kesalahan saat menulis ke %1: %2</translation>
+ <translation>Kesalahan tulis saat menulis ke %1: %2</translation>
</message>
<message>
<source>Socket error on %1: %2</source>
- <translation type="unfinished">Kesalahan soket pada %1: %2</translation>
+ <translation>Kesalahan soket pada %1: %2</translation>
</message>
<message>
<source>Remote host closed the connection prematurely on %1</source>
- <translation type="unfinished">Host remote menutup koneksi secara dini pada %1</translation>
+ <translation>Host remote menutup koneksi secara dini pada %1</translation>
</message>
</context>
<context>
@@ -3444,21 +3446,21 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>No suitable proxy found</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ditemukan proksi yang cocok</translation>
</message>
</context>
<context>
<name>QNetworkAccessManager</name>
<message>
<source>Network access is disabled.</source>
- <translation type="unfinished"></translation>
+ <translation>Akses jaringan dinonaktifkan.</translation>
</message>
</context>
<context>
<name>QNetworkReply</name>
<message>
<source>Error downloading %1 - server replied: %2</source>
- <translation type="vanished">Kesalahan mendownload %1 - server menjawab: %2</translation>
+ <translation>Kesalahan mendownload %1 - server menjawab: %2</translation>
</message>
<message>
<source>Protocol "%1" is unknown</source>
@@ -3466,34 +3468,34 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Error transferring %1 - server replied: %2</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat menransfer %1 - server menjawab: %2</translation>
</message>
<message>
<source>Background request not allowed.</source>
- <translation type="unfinished"></translation>
+ <translation>Permintaan latar belakang tidak diizinkan.</translation>
</message>
<message>
<source>Network session error.</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan sesi jaringan.</translation>
</message>
<message>
<source>backend start error.</source>
- <translation type="unfinished"></translation>
+ <translation>kesalahan memulai backend.</translation>
</message>
<message>
<source>Temporary network failure.</source>
- <translation type="unfinished"></translation>
+ <translation>Kegagalan jaringan temporer.</translation>
</message>
</context>
<context>
<name>QNetworkReplyHttpImpl</name>
<message>
<source>Operation canceled</source>
- <translation type="unfinished">Operasi dibatalkan</translation>
+ <translation>Operasi dibatalkan</translation>
</message>
<message>
<source>No suitable proxy found</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ditemukan proksi yang cocok</translation>
</message>
</context>
<context>
@@ -3507,30 +3509,30 @@ Anda tetap ingin menghapusnya?</translation>
<name>QNetworkSession</name>
<message>
<source>Invalid configuration.</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurasi tidak valid.</translation>
</message>
</context>
<context>
<name>QNetworkSessionPrivateImpl</name>
<message>
<source>Unknown session error.</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan sesi yang tidak dikenal.</translation>
</message>
<message>
<source>The session was aborted by the user or system.</source>
- <translation type="unfinished"></translation>
+ <translation>Sesi digugurkan oleh pengguna atau sistem.</translation>
</message>
<message>
<source>The requested operation is not supported by the system.</source>
- <translation type="unfinished"></translation>
+ <translation>Operasi yang diminta tidak didukung oleh sistem.</translation>
</message>
<message>
<source>The specified configuration cannot be used.</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurasi yang dinyatakan tidak dapat dipakai.</translation>
</message>
<message>
<source>Roaming was aborted or is not possible.</source>
- <translation type="unfinished"></translation>
+ <translation>Roaming digugurkan atau tidak mungkin.</translation>
</message>
</context>
<context>
@@ -3585,7 +3587,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Unable to execute select statement</source>
- <translation type="vanished">Tak bisa mengeksekusi pernyataan select</translation>
+ <translation>Tak bisa mengeksekusi pernyataan select</translation>
</message>
<message>
<source>Unable to execute statement</source>
@@ -3593,7 +3595,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Unable to get statement type</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa mendapat tipe pernyataan</translation>
</message>
</context>
<context>
@@ -3604,7 +3606,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Unable to connect - Driver doesn't support all needed functionality</source>
- <translation type="vanished">Tak bisa menyambung - Driver tak mendukung semua fungsionalitas yang diperlukan</translation>
+ <translation>Tak bisa menyambung - Driver tak mendukung semua fungsionalitas yang diperlukan</translation>
</message>
<message>
<source>Unable to disable autocommit</source>
@@ -3624,7 +3626,7 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Unable to connect - Driver doesn't support all functionality required</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa menyambung - Driver tak mendukung semua fungsionalitas yang diperlukan</translation>
</message>
</context>
<context>
@@ -3670,42 +3672,42 @@ Anda tetap ingin menghapusnya?</translation>
<name>QObject</name>
<message>
<source>Operation not supported on %1</source>
- <translation type="vanished">Operasi tak didukung pada %1</translation>
+ <translation>Operasi tak didukung pada %1</translation>
</message>
<message>
<source>Invalid URI: %1</source>
- <translation type="vanished">URI tak valid: %1</translation>
+ <translation>URI tak valid: %1</translation>
</message>
<message>
<source>Write error writing to %1: %2</source>
- <translation type="vanished">Kesalahan saat menulis ke %1: %2</translation>
+ <translation>Kesalahan saat menulis ke %1: %2</translation>
</message>
<message>
<source>Read error reading from %1: %2</source>
- <translation type="vanished">Kesalahan saat membaca dari %1: %2</translation>
+ <translation>Kesalahan saat membaca dari %1: %2</translation>
</message>
<message>
<source>Socket error on %1: %2</source>
- <translation type="vanished">Kesalahan soket pada %1: %2</translation>
+ <translation>Kesalahan soket pada %1: %2</translation>
</message>
<message>
<source>Remote host closed the connection prematurely on %1</source>
- <translation type="vanished">Host remote menutup koneksi secara dini pada %1</translation>
+ <translation>Host remote menutup koneksi secara dini pada %1</translation>
</message>
<message>
<source>Protocol error: packet of size 0 received</source>
- <translation type="vanished">Kesalahan protokol: paket berukuran 0 diterima</translation>
+ <translation>Kesalahan protokol: paket berukuran 0 diterima</translation>
</message>
</context>
<context>
<name>QPPDOptionsModel</name>
<message>
<source>Name</source>
- <translation type="vanished">Nama</translation>
+ <translation>Nama</translation>
</message>
<message>
<source>Value</source>
- <translation type="vanished">Nilai</translation>
+ <translation>Nilai</translation>
</message>
</context>
<context>
@@ -3750,7 +3752,7 @@ Anda tetap ingin menghapusnya?</translation>
<name>QPageSetupWidget</name>
<message>
<source>Centimeters (cm)</source>
- <translation type="vanished">Sentimeter (cm)</translation>
+ <translation>Sentimeter (cm)</translation>
</message>
<message>
<source>Millimeters (mm)</source>
@@ -3830,61 +3832,61 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Page Layout</source>
- <translation type="unfinished"></translation>
+ <translation>Tata Letak Halaman</translation>
</message>
<message>
<source>Page order:</source>
- <translation type="unfinished"></translation>
+ <translation>Urutan halaman:</translation>
</message>
<message>
<source>Pages per sheet:</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman per lembar:</translation>
</message>
<message>
<source>Pica (P̸)</source>
- <translation type="unfinished"></translation>
+ <translation>Pica (P̸)</translation>
</message>
<message>
<source>Didot (DD)</source>
- <translation type="unfinished"></translation>
+ <translation>Didot (DD)</translation>
</message>
<message>
<source>Cicero (CC)</source>
- <translation type="unfinished"></translation>
+ <translation>Cicero (CC)</translation>
</message>
<message>
<source>Custom</source>
- <translation type="unfinished">Gubahan</translation>
+ <translation>Ubahan</translation>
</message>
<message>
<source>mm</source>
<extracomment>Unit 'Millimeter'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>mm</translation>
</message>
<message>
<source>pt</source>
<extracomment>Unit 'Points'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>pt</translation>
</message>
<message>
<source>in</source>
<extracomment>Unit 'Inch'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>in</translation>
</message>
<message>
<source>P̸</source>
<extracomment>Unit 'Pica'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>P̸</translation>
</message>
<message>
<source>DD</source>
<extracomment>Unit 'Didot'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>DD</translation>
</message>
<message>
<source>CC</source>
<extracomment>Unit 'Cicero'</extracomment>
- <translation type="unfinished"></translation>
+ <translation>CC</translation>
</message>
</context>
<context>
@@ -3892,285 +3894,285 @@ Anda tetap ingin menghapusnya?</translation>
<message>
<source>Custom (%1mm x %2mm)</source>
<extracomment>Custom size name in millimeters</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1mm x %2mm)</translation>
</message>
<message>
<source>Custom (%1pt x %2pt)</source>
<extracomment>Custom size name in points</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1pt x %2pt)</translation>
</message>
<message>
<source>Custom (%1in x %2in)</source>
<extracomment>Custom size name in inches</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1in x %2in)</translation>
</message>
<message>
<source>Custom (%1pc x %2pc)</source>
<extracomment>Custom size name in picas</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1pc x %2pc)</translation>
</message>
<message>
<source>Custom (%1DD x %2DD)</source>
<extracomment>Custom size name in didots</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1DD x %2DD)</translation>
</message>
<message>
<source>Custom (%1CC x %2CC)</source>
<extracomment>Custom size name in ciceros</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Ubahan (%1CC x %2CC)</translation>
</message>
<message>
<source>%1 x %2 in</source>
<extracomment>Page size in 'Inch'.</extracomment>
- <translation type="unfinished"></translation>
+ <translation>%1 x %2 in</translation>
</message>
<message>
<source>A0</source>
- <translation type="unfinished">A0</translation>
+ <translation>A0</translation>
</message>
<message>
<source>A1</source>
- <translation type="unfinished">A1</translation>
+ <translation>A1</translation>
</message>
<message>
<source>A2</source>
- <translation type="unfinished">A2</translation>
+ <translation>A2</translation>
</message>
<message>
<source>A3</source>
- <translation type="unfinished">A3</translation>
+ <translation>A3</translation>
</message>
<message>
<source>A4</source>
- <translation type="unfinished">A4</translation>
+ <translation>A4</translation>
</message>
<message>
<source>A5</source>
- <translation type="unfinished">A5</translation>
+ <translation>A5</translation>
</message>
<message>
<source>A6</source>
- <translation type="unfinished">A6</translation>
+ <translation>A6</translation>
</message>
<message>
<source>A7</source>
- <translation type="unfinished">A7</translation>
+ <translation>A7</translation>
</message>
<message>
<source>A8</source>
- <translation type="unfinished">A8</translation>
+ <translation>A8</translation>
</message>
<message>
<source>A9</source>
- <translation type="unfinished">A9</translation>
+ <translation>A9</translation>
</message>
<message>
<source>A10</source>
- <translation type="unfinished">A10</translation>
+ <translation>A10</translation>
</message>
<message>
<source>B0</source>
- <translation type="unfinished">B0</translation>
+ <translation>B0</translation>
</message>
<message>
<source>B1</source>
- <translation type="unfinished">B1</translation>
+ <translation>B1</translation>
</message>
<message>
<source>B2</source>
- <translation type="unfinished">B2</translation>
+ <translation>B2</translation>
</message>
<message>
<source>B3</source>
- <translation type="unfinished">B3</translation>
+ <translation>B3</translation>
</message>
<message>
<source>B4</source>
- <translation type="unfinished">B4</translation>
+ <translation>B4</translation>
</message>
<message>
<source>B5</source>
- <translation type="unfinished">B5</translation>
+ <translation>B5</translation>
</message>
<message>
<source>B6</source>
- <translation type="unfinished">B6</translation>
+ <translation>B6</translation>
</message>
<message>
<source>B7</source>
- <translation type="unfinished">B7</translation>
+ <translation>B7</translation>
</message>
<message>
<source>B8</source>
- <translation type="unfinished">B8</translation>
+ <translation>B8</translation>
</message>
<message>
<source>B9</source>
- <translation type="unfinished">B9</translation>
+ <translation>B9</translation>
</message>
<message>
<source>B10</source>
- <translation type="unfinished">B10</translation>
+ <translation>B10</translation>
</message>
<message>
<source>Executive (7.5 x 10 in)</source>
- <translation type="unfinished"></translation>
+ <translation>Executive (7.5 x 10 in)</translation>
</message>
<message>
<source>Executive (7.25 x 10.5 in)</source>
- <translation type="unfinished"></translation>
+ <translation>Executive (7.25 x 10.5 in)</translation>
</message>
<message>
<source>Folio (8.27 x 13 in)</source>
- <translation type="unfinished"></translation>
+ <translation>Folio (8.27 x 13 in)</translation>
</message>
<message>
<source>Legal</source>
- <translation type="unfinished">Legal</translation>
+ <translation>Legal</translation>
</message>
<message>
<source>Letter / ANSI A</source>
- <translation type="unfinished"></translation>
+ <translation>Letter / ANSI A</translation>
</message>
<message>
<source>Tabloid / ANSI B</source>
- <translation type="unfinished"></translation>
+ <translation>Tabloid / ANSI B</translation>
</message>
<message>
<source>Ledger / ANSI B</source>
- <translation type="unfinished"></translation>
+ <translation>Ledger / ANSI B</translation>
</message>
<message>
<source>Custom</source>
- <translation type="unfinished">Gubahan</translation>
+ <translation>Ubahan</translation>
</message>
<message>
<source>A3 Extra</source>
- <translation type="unfinished"></translation>
+ <translation>A3 Ekstra</translation>
</message>
<message>
<source>A4 Extra</source>
- <translation type="unfinished"></translation>
+ <translation>A4 Ekstra</translation>
</message>
<message>
<source>A4 Plus</source>
- <translation type="unfinished"></translation>
+ <translation>A4 Plus</translation>
</message>
<message>
<source>A4 Small</source>
- <translation type="unfinished"></translation>
+ <translation>A4 Kecil</translation>
</message>
<message>
<source>A5 Extra</source>
- <translation type="unfinished"></translation>
+ <translation>A5 Ekstra</translation>
</message>
<message>
<source>B5 Extra</source>
- <translation type="unfinished"></translation>
+ <translation>B5 Ekstra</translation>
</message>
<message>
<source>JIS B0</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B0</translation>
</message>
<message>
<source>JIS B1</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B1</translation>
</message>
<message>
<source>JIS B2</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B2</translation>
</message>
<message>
<source>JIS B3</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B3</translation>
</message>
<message>
<source>JIS B4</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B4</translation>
</message>
<message>
<source>JIS B5</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B5</translation>
</message>
<message>
<source>JIS B6</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B6</translation>
</message>
<message>
<source>JIS B7</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B7</translation>
</message>
<message>
<source>JIS B8</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B8</translation>
</message>
<message>
<source>JIS B9</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B9</translation>
</message>
<message>
<source>JIS B10</source>
- <translation type="unfinished"></translation>
+ <translation>JIS B10</translation>
</message>
<message>
<source>ANSI C</source>
- <translation type="unfinished"></translation>
+ <translation>ANSI C</translation>
</message>
<message>
<source>ANSI D</source>
- <translation type="unfinished"></translation>
+ <translation>ANSI D</translation>
</message>
<message>
<source>ANSI E</source>
- <translation type="unfinished"></translation>
+ <translation>ANSI E</translation>
</message>
<message>
<source>Legal Extra</source>
- <translation type="unfinished"></translation>
+ <translation>Legal Ekstra</translation>
</message>
<message>
<source>Letter Extra</source>
- <translation type="unfinished"></translation>
+ <translation>Letter Ekstra</translation>
</message>
<message>
<source>Letter Plus</source>
- <translation type="unfinished"></translation>
+ <translation>Letter Plus</translation>
</message>
<message>
<source>Letter Small</source>
- <translation type="unfinished"></translation>
+ <translation>Letter Kecil</translation>
</message>
<message>
<source>Tabloid Extra</source>
- <translation type="unfinished"></translation>
+ <translation>Tabloid Ekstra</translation>
</message>
<message>
<source>Architect A</source>
- <translation type="unfinished"></translation>
+ <translation>Architect A</translation>
</message>
<message>
<source>Architect B</source>
- <translation type="unfinished"></translation>
+ <translation>Architect B</translation>
</message>
<message>
<source>Architect C</source>
- <translation type="unfinished"></translation>
+ <translation>Architect C</translation>
</message>
<message>
<source>Architect D</source>
- <translation type="unfinished"></translation>
+ <translation>Architect D</translation>
</message>
<message>
<source>Architect E</source>
- <translation type="unfinished"></translation>
+ <translation>Architect E</translation>
</message>
<message>
<source>Note</source>
- <translation type="unfinished"></translation>
+ <translation>Note</translation>
</message>
<message>
<source>Quarto</source>
- <translation type="unfinished"></translation>
+ <translation>Kuarto</translation>
</message>
<message>
<source>Statement</source>
@@ -4178,31 +4180,31 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Super A</source>
- <translation type="unfinished"></translation>
+ <translation>Super A</translation>
</message>
<message>
<source>Super B</source>
- <translation type="unfinished"></translation>
+ <translation>Super B</translation>
</message>
<message>
<source>Postcard</source>
- <translation type="unfinished"></translation>
+ <translation>Kartu Pos</translation>
</message>
<message>
<source>Double Postcard</source>
- <translation type="unfinished"></translation>
+ <translation>Kartu Pos Ganda</translation>
</message>
<message>
<source>PRC 16K</source>
- <translation type="unfinished"></translation>
+ <translation>PRC 16K</translation>
</message>
<message>
<source>PRC 32K</source>
- <translation type="unfinished"></translation>
+ <translation>PRC 32K</translation>
</message>
<message>
<source>PRC 32K Big</source>
- <translation type="unfinished"></translation>
+ <translation>PRC 32K Besar</translation>
</message>
<message>
<source>Fan-fold US (14.875 x 11 in)</source>
@@ -4218,226 +4220,226 @@ Anda tetap ingin menghapusnya?</translation>
</message>
<message>
<source>Envelope B4</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop B4</translation>
</message>
<message>
<source>Envelope B5</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop B5</translation>
</message>
<message>
<source>Envelope B6</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop B6</translation>
</message>
<message>
<source>Envelope C0</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C0</translation>
</message>
<message>
<source>Envelope C1</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C1</translation>
</message>
<message>
<source>Envelope C2</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C2</translation>
</message>
<message>
<source>Envelope C3</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C3</translation>
</message>
<message>
<source>Envelope C4</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C4</translation>
</message>
<message>
<source>Envelope C5</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C5</translation>
</message>
<message>
<source>Envelope C6</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C6</translation>
</message>
<message>
<source>Envelope C65</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C65</translation>
</message>
<message>
<source>Envelope C7</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop C7</translation>
</message>
<message>
<source>Envelope DL</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop DL</translation>
</message>
<message>
<source>Envelope US 9</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop US 9</translation>
</message>
<message>
<source>Envelope US 10</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop US 10</translation>
</message>
<message>
<source>Envelope US 11</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop US 11</translation>
</message>
<message>
<source>Envelope US 12</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop US 12</translation>
</message>
<message>
<source>Envelope US 14</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop US 14</translation>
</message>
<message>
<source>Envelope Monarch</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Monarch</translation>
</message>
<message>
<source>Envelope Personal</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Personal</translation>
</message>
<message>
<source>Envelope Chou 3</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Chou 3</translation>
</message>
<message>
<source>Envelope Chou 4</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Chou 4</translation>
</message>
<message>
<source>Envelope Invite</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Undangan</translation>
</message>
<message>
<source>Envelope Italian</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Italia</translation>
</message>
<message>
<source>Envelope Kaku 2</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Kaku 2</translation>
</message>
<message>
<source>Envelope Kaku 3</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop Kaku 3</translation>
</message>
<message>
<source>Envelope PRC 1</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 1</translation>
</message>
<message>
<source>Envelope PRC 2</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 2</translation>
</message>
<message>
<source>Envelope PRC 3</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 3</translation>
</message>
<message>
<source>Envelope PRC 4</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 4</translation>
</message>
<message>
<source>Envelope PRC 5</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 5</translation>
</message>
<message>
<source>Envelope PRC 6</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 6</translation>
</message>
<message>
<source>Envelope PRC 7</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 7</translation>
</message>
<message>
<source>Envelope PRC 8</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 8</translation>
</message>
<message>
<source>Envelope PRC 9</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 9</translation>
</message>
<message>
<source>Envelope PRC 10</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop PRC 10</translation>
</message>
<message>
<source>Envelope You 4</source>
- <translation type="unfinished"></translation>
+ <translation>Amplop You 4</translation>
</message>
</context>
<context>
<name>QPlatformTheme</name>
<message>
<source>OK</source>
- <translation type="unfinished">OK</translation>
+ <translation>OK</translation>
</message>
<message>
<source>Save</source>
- <translation type="unfinished">Simpan</translation>
+ <translation>Simpan</translation>
</message>
<message>
<source>Save All</source>
- <translation type="unfinished">Simpan Semua</translation>
+ <translation>Simpan Semua</translation>
</message>
<message>
<source>Open</source>
- <translation type="unfinished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>&Yes</source>
- <translation type="unfinished">&Ya</translation>
+ <translation>&Ya</translation>
</message>
<message>
<source>Yes to &All</source>
- <translation type="unfinished">Ya untuk Semu&a</translation>
+ <translation>Ya untuk Semu&a</translation>
</message>
<message>
<source>&No</source>
- <translation type="unfinished">&Tidak</translation>
+ <translation>&Tidak</translation>
</message>
<message>
<source>N&o to All</source>
- <translation type="unfinished">T&idak untuk Semua</translation>
+ <translation>T&idak untuk Semua</translation>
</message>
<message>
<source>Abort</source>
- <translation type="unfinished">Gugurkan</translation>
+ <translation>Gugurkan</translation>
</message>
<message>
<source>Retry</source>
- <translation type="unfinished">Coba Lagi</translation>
+ <translation>Coba Lagi</translation>
</message>
<message>
<source>Ignore</source>
- <translation type="unfinished">Abaikan</translation>
+ <translation>Abaikan</translation>
</message>
<message>
<source>Close</source>
- <translation type="unfinished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Cancel</source>
- <translation type="unfinished">Batal</translation>
+ <translation>Batal</translation>
</message>
<message>
<source>Discard</source>
- <translation type="unfinished">Buang</translation>
+ <translation>Buang</translation>
</message>
<message>
<source>Help</source>
- <translation type="unfinished">Bantuan</translation>
+ <translation>Bantuan</translation>
</message>
<message>
<source>Apply</source>
- <translation type="unfinished">Terapkan</translation>
+ <translation>Terapkan</translation>
</message>
<message>
<source>Reset</source>
- <translation type="unfinished">Reset</translation>
+ <translation>Reset</translation>
</message>
<message>
<source>Restore Defaults</source>
- <translation type="unfinished">Kembalikan Bawaan</translation>
+ <translation>Kembalikan Bawaan</translation>
</message>
</context>
<context>
@@ -4455,15 +4457,15 @@ Anda tetap ingin menghapusnya?</translation>
<name>QPrintDialog</name>
<message>
<source>locally connected</source>
- <translation type="vanished">tersambung secara lokal</translation>
+ <translation>tersambung secara lokal</translation>
</message>
<message>
<source>Aliases: %1</source>
- <translation type="vanished">Alias: %1</translation>
+ <translation>Alias: %1</translation>
</message>
<message>
<source>unknown</source>
- <translation type="vanished">tak dikenal</translation>
+ <translation>tak dikenal</translation>
</message>
<message>
<source>Print To File ...</source>
@@ -4489,127 +4491,127 @@ Silakan pilih nama file lain.</translation>
</message>
<message>
<source>A0</source>
- <translation type="vanished">A0</translation>
+ <translation>A0</translation>
</message>
<message>
<source>A1</source>
- <translation type="vanished">A1</translation>
+ <translation>A1</translation>
</message>
<message>
<source>A2</source>
- <translation type="vanished">A2</translation>
+ <translation>A2</translation>
</message>
<message>
<source>A3</source>
- <translation type="vanished">A3</translation>
+ <translation>A3</translation>
</message>
<message>
<source>A4</source>
- <translation type="vanished">A4</translation>
+ <translation>A4</translation>
</message>
<message>
<source>A5</source>
- <translation type="vanished">A5</translation>
+ <translation>A5</translation>
</message>
<message>
<source>A6</source>
- <translation type="vanished">A6</translation>
+ <translation>A6</translation>
</message>
<message>
<source>A7</source>
- <translation type="vanished">A7</translation>
+ <translation>A7</translation>
</message>
<message>
<source>A8</source>
- <translation type="vanished">A8</translation>
+ <translation>A8</translation>
</message>
<message>
<source>A9</source>
- <translation type="vanished">A9</translation>
+ <translation>A9</translation>
</message>
<message>
<source>B0</source>
- <translation type="vanished">B0</translation>
+ <translation>B0</translation>
</message>
<message>
<source>B1</source>
- <translation type="vanished">B1</translation>
+ <translation>B1</translation>
</message>
<message>
<source>B2</source>
- <translation type="vanished">B2</translation>
+ <translation>B2</translation>
</message>
<message>
<source>B3</source>
- <translation type="vanished">B3</translation>
+ <translation>B3</translation>
</message>
<message>
<source>B4</source>
- <translation type="vanished">B4</translation>
+ <translation>B4</translation>
</message>
<message>
<source>B5</source>
- <translation type="vanished">B5</translation>
+ <translation>B5</translation>
</message>
<message>
<source>B6</source>
- <translation type="vanished">B6</translation>
+ <translation>B6</translation>
</message>
<message>
<source>B7</source>
- <translation type="vanished">B7</translation>
+ <translation>B7</translation>
</message>
<message>
<source>B8</source>
- <translation type="vanished">B8</translation>
+ <translation>B8</translation>
</message>
<message>
<source>B9</source>
- <translation type="vanished">B9</translation>
+ <translation>B9</translation>
</message>
<message>
<source>B10</source>
- <translation type="vanished">B10</translation>
+ <translation>B10</translation>
</message>
<message>
<source>C5E</source>
- <translation type="vanished">C5E</translation>
+ <translation>C5E</translation>
</message>
<message>
<source>DLE</source>
- <translation type="vanished">DLE</translation>
+ <translation>DLE</translation>
</message>
<message>
<source>Executive</source>
- <translation type="vanished">Eksekutif</translation>
+ <translation>Eksekutif</translation>
</message>
<message>
<source>Folio</source>
- <translation type="vanished">Folio</translation>
+ <translation>Folio</translation>
</message>
<message>
<source>Ledger</source>
- <translation type="vanished">Ledger</translation>
+ <translation>Ledger</translation>
</message>
<message>
<source>Legal</source>
- <translation type="vanished">Legal</translation>
+ <translation>Legal</translation>
</message>
<message>
<source>Letter</source>
- <translation type="vanished">Letter</translation>
+ <translation>Letter</translation>
</message>
<message>
<source>Tabloid</source>
- <translation type="vanished">Tabloid</translation>
+ <translation>Tabloid</translation>
</message>
<message>
<source>US Common #10 Envelope</source>
- <translation type="vanished">Amplop Biasa #10 AS</translation>
+ <translation>Amplop Biasa #10 AS</translation>
</message>
<message>
<source>Custom</source>
- <translation type="vanished">Gubahan</translation>
+ <translation>Gubahan</translation>
</message>
<message>
<source>&Options >></source>
@@ -4629,7 +4631,7 @@ Silakan pilih nama file lain.</translation>
</message>
<message>
<source>Print to File (Postscript)</source>
- <translation type="vanished">Cetak ke File (Postscript)</translation>
+ <translation>Cetak ke File (Postscript)</translation>
</message>
<message>
<source>Local file</source>
@@ -4637,83 +4639,83 @@ Silakan pilih nama file lain.</translation>
</message>
<message>
<source>Write %1 file</source>
- <translation type="vanished">Tulis file %1</translation>
+ <translation>Tulis file %1</translation>
</message>
<message>
<source>Print</source>
- <translation type="unfinished"></translation>
+ <translation>Cetak</translation>
</message>
<message>
<source>Left to Right, Top to Bottom</source>
- <translation type="unfinished"></translation>
+ <translation>Kiri ke Kanan, Puncak ke Dasar</translation>
</message>
<message>
<source>Left to Right, Bottom to Top</source>
- <translation type="unfinished"></translation>
+ <translation>Kiri ke Kanan, Dasar ke Puncak</translation>
</message>
<message>
<source>Right to Left, Bottom to Top</source>
- <translation type="unfinished"></translation>
+ <translation>Kanan ke Kiri, Dasar ke Puncak</translation>
</message>
<message>
<source>Right to Left, Top to Bottom</source>
- <translation type="unfinished"></translation>
+ <translation>Kanan ke Kiri, Puncak ke Dasar</translation>
</message>
<message>
<source>Bottom to Top, Left to Right</source>
- <translation type="unfinished"></translation>
+ <translation>Dasar ke Puncak, Kiri ke Kanan</translation>
</message>
<message>
<source>Bottom to Top, Right to Left</source>
- <translation type="unfinished"></translation>
+ <translation>Dasar ke Puncak, Kanan ke Kiri</translation>
</message>
<message>
<source>Top to Bottom, Left to Right</source>
- <translation type="unfinished"></translation>
+ <translation>Puncak ke Dasar, Kiri ke Kanan</translation>
</message>
<message>
<source>Top to Bottom, Right to Left</source>
- <translation type="unfinished"></translation>
+ <translation>Puncak ke Dasar, Kanan ke Kiri</translation>
</message>
<message>
<source>1 (1x1)</source>
- <translation type="unfinished"></translation>
+ <translation>1 (1x1)</translation>
</message>
<message>
<source>2 (2x1)</source>
- <translation type="unfinished"></translation>
+ <translation>2 (2x1)</translation>
</message>
<message>
<source>4 (2x2)</source>
- <translation type="unfinished"></translation>
+ <translation>4 (2x2)</translation>
</message>
<message>
<source>6 (2x3)</source>
- <translation type="unfinished"></translation>
+ <translation>6 (2x3)</translation>
</message>
<message>
<source>9 (3x3)</source>
- <translation type="unfinished"></translation>
+ <translation>9 (3x3)</translation>
</message>
<message>
<source>16 (4x4)</source>
- <translation type="unfinished"></translation>
+ <translation>16 (4x4)</translation>
</message>
<message>
<source>All Pages</source>
- <translation type="unfinished"></translation>
+ <translation>Semua Halaman</translation>
</message>
<message>
<source>Odd Pages</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Ganjil</translation>
</message>
<message>
<source>Even Pages</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Genap</translation>
</message>
<message>
<source>Write PDF file</source>
- <translation type="unfinished"></translation>
+ <translation>Tulis berkas PDF</translation>
</message>
<message>
<source>Options 'Pages Per Sheet' and 'Page Set' cannot be used together.
@@ -4726,11 +4728,11 @@ Please turn one of those options off.</source>
</message>
<message>
<source>OK</source>
- <translation type="unfinished">OK</translation>
+ <translation>OK</translation>
</message>
<message>
<source>Automatic</source>
- <translation type="unfinished"></translation>
+ <translation>Otomatis</translation>
</message>
</context>
<context>
@@ -4805,26 +4807,26 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>%1%</source>
- <translation type="unfinished"></translation>
+ <translation>%1%</translation>
</message>
<message>
<source>Export to PDF</source>
- <translation type="unfinished"></translation>
+ <translation>Ekspor ke PDF</translation>
</message>
</context>
<context>
<name>QPrintPropertiesDialog</name>
<message>
<source>Printer Properties</source>
- <translation type="unfinished"></translation>
+ <translation>Properti Pencetak</translation>
</message>
<message>
<source>Job Options</source>
- <translation type="unfinished"></translation>
+ <translation>Opsi Tugas</translation>
</message>
</context>
<context>
@@ -4839,7 +4841,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Advanced</source>
- <translation type="vanished">Tingkat lanjut</translation>
+ <translation>Tingkat lanjut</translation>
</message>
</context>
<context>
@@ -4922,11 +4924,11 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Current Page</source>
- <translation type="unfinished"></translation>
+ <translation>Halaman Saat Ini</translation>
</message>
<message>
<source>Page Set:</source>
- <translation type="unfinished"></translation>
+ <translation>Set Halaman:</translation>
</message>
</context>
<context>
@@ -4972,43 +4974,43 @@ Please turn one of those options off.</source>
<name>QProcess</name>
<message>
<source>Process failed to start</source>
- <translation type="unfinished"></translation>
+ <translation>Proses gagal mulai</translation>
</message>
<message>
<source>Process crashed</source>
- <translation type="unfinished"></translation>
+ <translation>Proses kres</translation>
</message>
<message>
<source>Process operation timed out</source>
- <translation type="unfinished"></translation>
+ <translation>Operasi proses habis waktu</translation>
</message>
<message>
<source>Error reading from process</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat membaca dari proses</translation>
</message>
<message>
<source>Error writing to process</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan saat menulis ke proses</translation>
</message>
<message>
<source>No program defined</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak ada program yang didefinisikan</translation>
</message>
<message>
<source>Could not open input redirection for reading</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membuka pengalihan masukan untuk membaca</translation>
</message>
<message>
<source>Resource error (fork failure): %1</source>
- <translation type="unfinished"></translation>
+ <translation>Kesalahan sumber daya (kegagalan fork): %1</translation>
</message>
<message>
<source>Could not open output redirection for writing</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa membuka pengalihan keluaran untuk menulis</translation>
</message>
<message>
<source>Process failed to start: %1</source>
- <translation type="unfinished"></translation>
+ <translation>Proses gagal mulai: %1</translation>
</message>
</context>
<context>
@@ -5022,28 +5024,28 @@ Please turn one of those options off.</source>
<name>QPushButton</name>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
</context>
<context>
<name>QQnxFileDialogHelper</name>
<message>
<source>All files (*.*)</source>
- <translation type="unfinished"></translation>
+ <translation>Semua berkas (*.*)</translation>
</message>
</context>
<context>
<name>QQnxFilePicker</name>
<message>
<source>Pick a file</source>
- <translation type="unfinished"></translation>
+ <translation>Pilih suatu berkas</translation>
</message>
</context>
<context>
<name>QRadioButton</name>
<message>
<source>Check</source>
- <translation type="vanished">Periksa</translation>
+ <translation>Periksa</translation>
</message>
</context>
<context>
@@ -5090,30 +5092,30 @@ Please turn one of those options off.</source>
</message>
<message>
<source>invalid interval</source>
- <translation type="unfinished"></translation>
+ <translation>interval tidak valid</translation>
</message>
<message>
<source>invalid category</source>
- <translation type="unfinished"></translation>
+ <translation>kategori tidak valid</translation>
</message>
</context>
<context>
<name>QRegularExpression</name>
<message>
<source>no error</source>
- <translation type="unfinished"></translation>
+ <translation>tidak ada kesalahan</translation>
</message>
<message>
<source>\ at end of pattern</source>
- <translation type="unfinished"></translation>
+ <translation>\ di akhir pola</translation>
</message>
<message>
<source>\c at end of pattern</source>
- <translation type="unfinished"></translation>
+ <translation>\c di akhir pola</translation>
</message>
<message>
<source>unrecognized character follows \</source>
- <translation type="unfinished"></translation>
+ <translation>karakter tak dikenal setelah \</translation>
</message>
<message>
<source>numbers out of order in {} quantifier</source>
@@ -5436,7 +5438,7 @@ Please turn one of those options off.</source>
<name>QSQLite2Driver</name>
<message>
<source>Error to open database</source>
- <translation type="vanished">Kesalahan membuka database</translation>
+ <translation>Kesalahan membuka database</translation>
</message>
<message>
<source>Unable to begin transaction</source>
@@ -5448,15 +5450,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Unable to rollback Transaction</source>
- <translation type="vanished">Tak bisa rollback transaksi</translation>
+ <translation>Tak bisa rollback transaksi</translation>
</message>
<message>
<source>Error opening database</source>
- <translation type="unfinished">Kesalahan saat membuka database</translation>
+ <translation>Kesalahan membuka database</translation>
</message>
<message>
<source>Unable to rollback transaction</source>
- <translation type="unfinished">Tak bisa rollback transaksi</translation>
+ <translation>Tak bisa rollback transaksi</translation>
</message>
</context>
<context>
@@ -5521,22 +5523,22 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Unable to execute multiple statements at a time</source>
- <translation type="unfinished"></translation>
+ <translation>Tak bisa mengeksekusi beberapa pernyataan pada satu saat</translation>
</message>
</context>
<context>
<name>QSaveFile</name>
<message>
<source>Existing file %1 is not writable</source>
- <translation type="unfinished"></translation>
+ <translation>Berkas %1 yang ada tidak dapat ditulisi</translation>
</message>
<message>
<source>Filename refers to a directory</source>
- <translation type="unfinished"></translation>
+ <translation>Nama berkas mengacu ke suatu direktori</translation>
</message>
<message>
<source>Writing canceled by application</source>
- <translation type="unfinished"></translation>
+ <translation>Penulisan dibatalkan oleh aplikasi</translation>
</message>
</context>
<context>
@@ -5595,15 +5597,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Line up</source>
- <translation type="vanished">Baris naik</translation>
+ <translation>Baris naik</translation>
</message>
<message>
<source>Position</source>
- <translation type="vanished">Posisi</translation>
+ <translation>Posisi</translation>
</message>
<message>
<source>Line down</source>
- <translation type="vanished">Baris turun</translation>
+ <translation>Baris turun</translation>
</message>
</context>
<context>
@@ -5634,7 +5636,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>%1: doesn't exists</source>
- <translation type="vanished">%1: tidak ada</translation>
+ <translation>%1: tidak ada</translation>
</message>
<message>
<source>%1: out of resources</source>
@@ -5650,7 +5652,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>%1: unix key file doesn't exists</source>
- <translation type="vanished">%1: file kunci unix tak ada</translation>
+ <translation>%1: file kunci unix tak ada</translation>
</message>
<message>
<source>%1: ftok failed</source>
@@ -5670,27 +5672,27 @@ Please turn one of those options off.</source>
</message>
<message>
<source>%1: bad name</source>
- <translation type="unfinished"></translation>
+ <translation>%1: nama buruk</translation>
</message>
<message>
<source>%1: UNIX key file doesn't exist</source>
- <translation type="unfinished"></translation>
+ <translation>%1: berkas kunci UNIX tidak ada</translation>
</message>
<message>
<source>%1: doesn't exist</source>
- <translation type="unfinished"></translation>
+ <translation>%1: tidak ada</translation>
</message>
<message>
<source>%1: invalid size</source>
- <translation type="unfinished"></translation>
+ <translation>%1: ukuran tak valid</translation>
</message>
<message>
<source>%1: key error</source>
- <translation type="unfinished"></translation>
+ <translation>%1: kesalahan kunci</translation>
</message>
<message>
<source>%1: size query failed</source>
- <translation type="unfinished"></translation>
+ <translation>%1: kueri ukuran gagal</translation>
</message>
</context>
<context>
@@ -6069,40 +6071,40 @@ Please turn one of those options off.</source>
<message>
<source>Media Pause</source>
<extracomment>Media player pause button</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Media Jeda</translation>
</message>
<message>
<source>Toggle Media Play/Pause</source>
<extracomment>Media player button to toggle between playing and paused</extracomment>
- <translation type="unfinished"></translation>
+ <translation>Jungkitkan Media Putar/Jeda</translation>
</message>
<message>
<source>Monitor Brightness Up</source>
- <translation type="unfinished"></translation>
+ <translation>Kecerahan Layar Naik</translation>
</message>
<message>
<source>Monitor Brightness Down</source>
- <translation type="unfinished"></translation>
+ <translation>Kecerahan Layar Turun</translation>
</message>
<message>
<source>Keyboard Light On/Off</source>
- <translation type="unfinished"></translation>
+ <translation>Cahaya Latar Papan Ketik Nyala/Mati</translation>
</message>
<message>
<source>Keyboard Brightness Up</source>
- <translation type="unfinished"></translation>
+ <translation>Kecerahan Cahaya Papan Ketik Naik</translation>
</message>
<message>
<source>Keyboard Brightness Down</source>
- <translation type="unfinished"></translation>
+ <translation>Kecerahan Cahaya Papan Ketik Turun</translation>
</message>
<message>
<source>Power Off</source>
- <translation type="unfinished"></translation>
+ <translation>Matikan Daya</translation>
</message>
<message>
<source>Wake Up</source>
- <translation type="unfinished"></translation>
+ <translation>Bangunkan</translation>
</message>
<message>
<source>Eject</source>
@@ -6114,11 +6116,11 @@ Please turn one of those options off.</source>
</message>
<message>
<source>WWW</source>
- <translation type="unfinished"></translation>
+ <translation>WWW</translation>
</message>
<message>
<source>Sleep</source>
- <translation type="unfinished"></translation>
+ <translation>Tidur</translation>
</message>
<message>
<source>LightBulb</source>
@@ -6126,15 +6128,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Shop</source>
- <translation type="unfinished"></translation>
+ <translation>Toko</translation>
</message>
<message>
<source>History</source>
- <translation type="unfinished"></translation>
+ <translation>Riwayat</translation>
</message>
<message>
<source>Add Favorite</source>
- <translation type="unfinished"></translation>
+ <translation>Tambah Favorit</translation>
</message>
<message>
<source>Hot Links</source>
@@ -6142,15 +6144,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Adjust Brightness</source>
- <translation type="unfinished"></translation>
+ <translation>Atur Kecerahan</translation>
</message>
<message>
<source>Finance</source>
- <translation type="unfinished"></translation>
+ <translation>Keuangan</translation>
</message>
<message>
<source>Community</source>
- <translation type="unfinished"></translation>
+ <translation>Komunitas</translation>
</message>
<message>
<source>Media Rewind</source>
@@ -6162,27 +6164,27 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Application Left</source>
- <translation type="unfinished"></translation>
+ <translation>Kiri Aplikasi</translation>
</message>
<message>
<source>Application Right</source>
- <translation type="unfinished"></translation>
+ <translation>Kanan Aplikasi</translation>
</message>
<message>
<source>Book</source>
- <translation type="unfinished"></translation>
+ <translation>Buku</translation>
</message>
<message>
<source>CD</source>
- <translation type="unfinished"></translation>
+ <translation>CD</translation>
</message>
<message>
<source>Calculator</source>
- <translation type="unfinished"></translation>
+ <translation>Kalkulator</translation>
</message>
<message>
<source>Clear</source>
- <translation type="unfinished">Bersihkan</translation>
+ <translation>Bersihkan</translation>
</message>
<message>
<source>Clear Grab</source>
@@ -6190,15 +6192,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Close</source>
- <translation type="unfinished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>Copy</source>
- <translation type="unfinished">Salin</translation>
+ <translation>Salin</translation>
</message>
<message>
<source>Cut</source>
- <translation type="unfinished">Potong</translation>
+ <translation>Potong</translation>
</message>
<message>
<source>Display</source>
@@ -6206,11 +6208,11 @@ Please turn one of those options off.</source>
</message>
<message>
<source>DOS</source>
- <translation type="unfinished"></translation>
+ <translation>DOS</translation>
</message>
<message>
<source>Documents</source>
- <translation type="unfinished"></translation>
+ <translation>Dokumen</translation>
</message>
<message>
<source>Spreadsheet</source>
@@ -6218,11 +6220,11 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Browser</source>
- <translation type="unfinished"></translation>
+ <translation>Peramban</translation>
</message>
<message>
<source>Game</source>
- <translation type="unfinished"></translation>
+ <translation>Permainan</translation>
</message>
<message>
<source>Go</source>
@@ -6230,7 +6232,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>iTouch</source>
- <translation type="unfinished"></translation>
+ <translation>iTouch</translation>
</message>
<message>
<source>Logoff</source>
@@ -6238,15 +6240,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Market</source>
- <translation type="unfinished"></translation>
+ <translation>Pasar</translation>
</message>
<message>
<source>Meeting</source>
- <translation type="unfinished"></translation>
+ <translation>Rapat</translation>
</message>
<message>
<source>Keyboard Menu</source>
- <translation type="unfinished"></translation>
+ <translation>Menu Papan Ketik</translation>
</message>
<message>
<source>Menu PB</source>
@@ -6258,7 +6260,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>News</source>
- <translation type="unfinished"></translation>
+ <translation>Berita</translation>
</message>
<message>
<source>Home Office</source>
@@ -6266,27 +6268,27 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Option</source>
- <translation type="unfinished"></translation>
+ <translation>Opsi</translation>
</message>
<message>
<source>Paste</source>
- <translation type="unfinished">Tempel</translation>
+ <translation>Tempel</translation>
</message>
<message>
<source>Phone</source>
- <translation type="unfinished"></translation>
+ <translation>Telepon</translation>
</message>
<message>
<source>Reply</source>
- <translation type="unfinished"></translation>
+ <translation>Jawab</translation>
</message>
<message>
<source>Reload</source>
- <translation type="unfinished">Muat Ulang</translation>
+ <translation>Muat Ulang</translation>
</message>
<message>
<source>Rotate Windows</source>
- <translation type="unfinished"></translation>
+ <translation>Putar Jendela</translation>
</message>
<message>
<source>Rotation PB</source>
@@ -6298,47 +6300,47 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Save</source>
- <translation type="unfinished">Simpan</translation>
+ <translation>Simpan</translation>
</message>
<message>
<source>Send</source>
- <translation type="unfinished"></translation>
+ <translation>Kirim</translation>
</message>
<message>
<source>Spellchecker</source>
- <translation type="unfinished"></translation>
+ <translation>Pemeriksa Ejaan</translation>
</message>
<message>
<source>Split Screen</source>
- <translation type="unfinished"></translation>
+ <translation>Belah Layar</translation>
</message>
<message>
<source>Support</source>
- <translation type="unfinished"></translation>
+ <translation>Dukungan</translation>
</message>
<message>
<source>Task Panel</source>
- <translation type="unfinished"></translation>
+ <translation>Panel Tugas</translation>
</message>
<message>
<source>Terminal</source>
- <translation type="unfinished"></translation>
+ <translation>Terminal</translation>
</message>
<message>
<source>Tools</source>
- <translation type="unfinished"></translation>
+ <translation>Perkakas</translation>
</message>
<message>
<source>Travel</source>
- <translation type="unfinished"></translation>
+ <translation>Perjalanan</translation>
</message>
<message>
<source>Video</source>
- <translation type="unfinished">Video</translation>
+ <translation>Video</translation>
</message>
<message>
<source>Word Processor</source>
- <translation type="unfinished"></translation>
+ <translation>Pengolah Kata</translation>
</message>
<message>
<source>XFer</source>
@@ -6354,7 +6356,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Away</source>
- <translation type="unfinished"></translation>
+ <translation>Pergi</translation>
</message>
<message>
<source>Messenger</source>
@@ -6362,7 +6364,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>WebCam</source>
- <translation type="unfinished"></translation>
+ <translation>WebCam</translation>
</message>
<message>
<source>Mail Forward</source>
@@ -6370,23 +6372,23 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Pictures</source>
- <translation type="unfinished"></translation>
+ <translation>Gambar</translation>
</message>
<message>
<source>Music</source>
- <translation type="unfinished">Musik</translation>
+ <translation>Musik</translation>
</message>
<message>
<source>Battery</source>
- <translation type="unfinished"></translation>
+ <translation>Baterai</translation>
</message>
<message>
<source>Bluetooth</source>
- <translation type="unfinished"></translation>
+ <translation>Bluetooth</translation>
</message>
<message>
<source>Wireless</source>
- <translation type="unfinished"></translation>
+ <translation>Nirkabel</translation>
</message>
<message>
<source>Ultra Wide Band</source>
@@ -6414,19 +6416,19 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Time</source>
- <translation type="unfinished"></translation>
+ <translation>Waktu</translation>
</message>
<message>
<source>Hibernate</source>
- <translation type="unfinished"></translation>
+ <translation>Hibernasi</translation>
</message>
<message>
<source>View</source>
- <translation type="unfinished"></translation>
+ <translation>Tilik</translation>
</message>
<message>
<source>Top Menu</source>
- <translation type="unfinished"></translation>
+ <translation>Menu Puncak</translation>
</message>
<message>
<source>Power Down</source>
@@ -6434,47 +6436,47 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Suspend</source>
- <translation type="unfinished"></translation>
+ <translation>Suspensi</translation>
</message>
<message>
<source>Microphone Mute</source>
- <translation type="unfinished"></translation>
+ <translation>Mikrofon Bisu</translation>
</message>
<message>
<source>Red</source>
- <translation type="unfinished"></translation>
+ <translation>Merah</translation>
</message>
<message>
<source>Green</source>
- <translation type="unfinished"></translation>
+ <translation>Hijau</translation>
</message>
<message>
<source>Yellow</source>
- <translation type="unfinished"></translation>
+ <translation>Kuning</translation>
</message>
<message>
<source>Blue</source>
- <translation type="unfinished"></translation>
+ <translation>Biru</translation>
</message>
<message>
<source>Channel Up</source>
- <translation type="unfinished"></translation>
+ <translation>Kanal Naik</translation>
</message>
<message>
<source>Channel Down</source>
- <translation type="unfinished"></translation>
+ <translation>Kanal Turun</translation>
</message>
<message>
<source>Guide</source>
- <translation type="unfinished"></translation>
+ <translation>Panduan</translation>
</message>
<message>
<source>Info</source>
- <translation type="unfinished"></translation>
+ <translation>Info</translation>
</message>
<message>
<source>Settings</source>
- <translation type="unfinished"></translation>
+ <translation>Setelan</translation>
</message>
<message>
<source>Microphone Volume Up</source>
@@ -6486,15 +6488,15 @@ Please turn one of those options off.</source>
</message>
<message>
<source>New</source>
- <translation type="unfinished"></translation>
+ <translation>Baru</translation>
</message>
<message>
<source>Open</source>
- <translation type="unfinished">Buka</translation>
+ <translation>Buka</translation>
</message>
<message>
<source>Find</source>
- <translation type="unfinished"></translation>
+ <translation>Cari</translation>
</message>
<message>
<source>Undo</source>
@@ -6531,51 +6533,51 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Kanji</source>
- <translation type="unfinished"></translation>
+ <translation>Kanji</translation>
</message>
<message>
<source>Muhenkan</source>
- <translation type="unfinished"></translation>
+ <translation>Muhenkan</translation>
</message>
<message>
<source>Henkan</source>
- <translation type="unfinished"></translation>
+ <translation>Henkan</translation>
</message>
<message>
<source>Romaji</source>
- <translation type="unfinished"></translation>
+ <translation>Romaji</translation>
</message>
<message>
<source>Hiragana</source>
- <translation type="unfinished"></translation>
+ <translation>Hiragana</translation>
</message>
<message>
<source>Katakana</source>
- <translation type="unfinished"></translation>
+ <translation>Katakana</translation>
</message>
<message>
<source>Hiragana Katakana</source>
- <translation type="unfinished"></translation>
+ <translation>Hiragana Katakana</translation>
</message>
<message>
<source>Zenkaku</source>
- <translation type="unfinished"></translation>
+ <translation></translation>
</message>
<message>
<source>Hankaku</source>
- <translation type="unfinished"></translation>
+ <translation>Hankaku</translation>
</message>
<message>
<source>Zenkaku Hankaku</source>
- <translation type="unfinished"></translation>
+ <translation>Zenkaku Hankaku</translation>
</message>
<message>
<source>Touroku</source>
- <translation type="unfinished"></translation>
+ <translation>Touroku</translation>
</message>
<message>
<source>Massyo</source>
- <translation type="unfinished"></translation>
+ <translation>Massyo</translation>
</message>
<message>
<source>Kana Lock</source>
@@ -6607,7 +6609,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Hangul</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul</translation>
</message>
<message>
<source>Hangul Start</source>
@@ -6619,31 +6621,31 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Hangul Hanja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul Hanja</translation>
</message>
<message>
<source>Hangul Jamo</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul Jamo</translation>
</message>
<message>
<source>Hangul Romaja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul Romaja</translation>
</message>
<message>
<source>Hangul Jeonja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul Jeonja</translation>
</message>
<message>
<source>Hangul Banja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul Banja</translation>
</message>
<message>
<source>Hangul PreHanja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul PreHanja</translation>
</message>
<message>
<source>Hangul PostHanja</source>
- <translation type="unfinished"></translation>
+ <translation>Hangul PostHanja</translation>
</message>
<message>
<source>Hangul Special</source>
@@ -6651,7 +6653,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Cancel</source>
- <translation type="unfinished">Batal</translation>
+ <translation>Batal</translation>
</message>
<message>
<source>Printer</source>
@@ -6671,7 +6673,7 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Exit</source>
- <translation type="unfinished"></translation>
+ <translation>Keluar</translation>
</message>
<message>
<source>Touchpad Toggle</source>
@@ -6687,37 +6689,37 @@ Please turn one of those options off.</source>
</message>
<message>
<source>Num</source>
- <translation type="unfinished"></translation>
+ <translation>Num</translation>
</message>
</context>
<context>
<name>QSlider</name>
<message>
<source>Page left</source>
- <translation type="vanished">Halaman kiri</translation>
+ <translation>Halaman kiri</translation>
</message>
<message>
<source>Page up</source>
- <translation type="vanished">Halaman naik</translation>
+ <translation>Halaman naik</translation>
</message>
<message>
<source>Position</source>
- <translation type="vanished">Posisi</translation>
+ <translation>Posisi</translation>
</message>
<message>
<source>Page right</source>
- <translation type="vanished">Halaman kanan</translation>
+ <translation>Halaman kanan</translation>
</message>
<message>
<source>Page down</source>
- <translation type="vanished">Halaman turun</translation>
+ <translation>Halaman turun</translation>
</message>
</context>
<context>
<name>QSocks5SocketEngine</name>
<message>
<source>Socks5 timeout error connecting to socks server</source>
- <translation type="vanished">Kesalahan habis waktu socks5 saat menyambung ke server socks</translation>
+ <translation>Kesalahan habis waktu socks5 saat menyambung ke server socks</translation>
</message>
<message>
<source>Network operation timed out</source>
@@ -7140,54 +7142,54 @@ Role of an accessible object</extracomment>
<name>QSpinBox</name>
<message>
<source>More</source>
- <translation type="vanished">Lebih</translation>
+ <translation>Lebih</translation>
</message>
<message>
<source>Less</source>
- <translation type="vanished">Kurang</translation>
+ <translation>Kurang</translation>
</message>
</context>
<context>
<name>QSql</name>
<message>
<source>Delete</source>
- <translation type="vanished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
<message>
<source>Delete this record?</source>
- <translation type="vanished">Hapus record ini?</translation>
+ <translation>Hapus record ini?</translation>
</message>
<message>
<source>Yes</source>
- <translation type="vanished">Ya</translation>
+ <translation>Ya</translation>
</message>
<message>
<source>No</source>
- <translation type="vanished">Tidak</translation>
+ <translation>Tidak</translation>
</message>
<message>
<source>Insert</source>
- <translation type="vanished">Sisipkan</translation>
+ <translation>Sisipkan</translation>
</message>
<message>
<source>Update</source>
- <translation type="vanished">Perbarui</translation>
+ <translation>Perbarui</translation>
</message>
<message>
<source>Save edits?</source>
- <translation type="vanished">Simpan edit?</translation>
+ <translation>Simpan edit?</translation>
</message>
<message>
<source>Cancel</source>
- <translation type="vanished">Batal</translation>
+ <translation>Batal</translation>
</message>
<message>
<source>Confirm</source>
- <translation type="vanished">Konfirmasi</translation>
+ <translation>Konfirmasi</translation>
</message>
<message>
<source>Cancel your edits?</source>
- <translation type="vanished">Batalkan edit Anda?</translation>
+ <translation>Batalkan edit Anda?</translation>
</message>
</context>
<context>
@@ -7234,7 +7236,7 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>Private key does not certificate public key, %1</source>
- <translation type="vanished">Kunci privat tak mensertifikasi kunci publik, %1</translation>
+ <translation>Kunci privat tak mensertifikasi kunci publik, %1</translation>
</message>
<message>
<source>Error when setting the elliptic curves (%1)</source>
@@ -7365,35 +7367,35 @@ Role of an accessible object</extracomment>
<name>QStandardPaths</name>
<message>
<source>Desktop</source>
- <translation type="unfinished"></translation>
+ <translation>Desktop</translation>
</message>
<message>
<source>Documents</source>
- <translation type="unfinished"></translation>
+ <translation>Dokumen</translation>
</message>
<message>
<source>Fonts</source>
- <translation type="unfinished">Font</translation>
+ <translation>Font</translation>
</message>
<message>
<source>Applications</source>
- <translation type="unfinished"></translation>
+ <translation>Aplikasi</translation>
</message>
<message>
<source>Music</source>
- <translation type="unfinished">Musik</translation>
+ <translation>Musik</translation>
</message>
<message>
<source>Movies</source>
- <translation type="unfinished"></translation>
+ <translation>Film</translation>
</message>
<message>
<source>Pictures</source>
- <translation type="unfinished"></translation>
+ <translation>Gambar</translation>
</message>
<message>
<source>Temporary Directory</source>
- <translation type="unfinished"></translation>
+ <translation>Direktori Sementara</translation>
</message>
<message>
<source>Home</source>
@@ -7401,11 +7403,11 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>Cache</source>
- <translation type="unfinished"></translation>
+ <translation>Singgahan</translation>
</message>
<message>
<source>Shared Data</source>
- <translation type="unfinished"></translation>
+ <translation>Data Bersama</translation>
</message>
<message>
<source>Runtime</source>
@@ -7413,27 +7415,27 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>Configuration</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurasi</translation>
</message>
<message>
<source>Shared Configuration</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurasi Bersama</translation>
</message>
<message>
<source>Shared Cache</source>
- <translation type="unfinished"></translation>
+ <translation>Singgahan Bersama</translation>
</message>
<message>
<source>Download</source>
- <translation type="unfinished"></translation>
+ <translation>Unduh</translation>
</message>
<message>
<source>Application Data</source>
- <translation type="unfinished"></translation>
+ <translation>Data Aplikasi</translation>
</message>
<message>
<source>Application Configuration</source>
- <translation type="unfinished"></translation>
+ <translation>Konfigurasi Aplikasi</translation>
</message>
</context>
<context>
@@ -7444,7 +7446,7 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>Missing default state in history state '%1'</source>
- <translation type="unfinished"></translation>
+ <translation>Kurang keadaan baku dalam keadaan riwayat '%1'</translation>
</message>
<message>
<source>No common ancestor for targets and source of transition from state '%1'</source>
@@ -7452,30 +7454,30 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>Unknown error</source>
- <translation type="unfinished">Kesalahan tak dikenal</translation>
+ <translation>Kesalahan tak dikenal</translation>
</message>
</context>
<context>
<name>QSystemSemaphore</name>
<message>
<source>%1: permission denied</source>
- <translation type="unfinished">%1: ijin ditolak</translation>
+ <translation>%1: izin ditolak</translation>
</message>
<message>
<source>%1: already exists</source>
- <translation type="unfinished">%1: telah ada</translation>
+ <translation>%1: telah ada</translation>
</message>
<message>
<source>%1: does not exist</source>
- <translation type="unfinished"></translation>
+ <translation>%1: tidak ada</translation>
</message>
<message>
<source>%1: out of resources</source>
- <translation type="unfinished">%1: kehabisan sumber daya</translation>
+ <translation>%1: kehabisan sumber daya</translation>
</message>
<message>
<source>%1: unknown error %2</source>
- <translation type="unfinished">%1: kesalahan tak dikenal %2</translation>
+ <translation>%1: kesalahan tak dikenal %2</translation>
</message>
</context>
<context>
@@ -7504,89 +7506,89 @@ Role of an accessible object</extracomment>
<name>QTcpServer</name>
<message>
<source>Operation on socket is not supported</source>
- <translation type="unfinished"></translation>
+ <translation>Operasi pada soket tidak didukung</translation>
</message>
</context>
<context>
<name>QTextControl</name>
<message>
<source>&Undo</source>
- <translation type="vanished">&Batalkan</translation>
+ <translation>&Batalkan</translation>
</message>
<message>
<source>&Redo</source>
- <translation type="vanished">&Jadi Lagi</translation>
+ <translation>&Jadi Lagi</translation>
</message>
<message>
<source>Cu&t</source>
- <translation type="vanished">Po&tong</translation>
+ <translation>Po&tong</translation>
</message>
<message>
<source>&Copy</source>
- <translation type="vanished">&Salin</translation>
+ <translation>&Salin</translation>
</message>
<message>
<source>Copy &Link Location</source>
- <translation type="vanished">Salin &Lokasi Taut</translation>
+ <translation>Salin &Lokasi Taut</translation>
</message>
<message>
<source>&Paste</source>
- <translation type="vanished">Tem&pel</translation>
+ <translation>Tem&pel</translation>
</message>
<message>
<source>Delete</source>
- <translation type="vanished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
<message>
<source>Select All</source>
- <translation type="vanished">Pilih Semua</translation>
+ <translation>Pilih Semua</translation>
</message>
</context>
<context>
<name>QToolButton</name>
<message>
<source>Press</source>
- <translation type="vanished">Tekan</translation>
+ <translation>Tekan</translation>
</message>
<message>
<source>Open</source>
- <translation type="vanished">Buka</translation>
+ <translation>Buka</translation>
</message>
</context>
<context>
<name>QUdpSocket</name>
<message>
<source>This platform does not support IPv6</source>
- <translation type="vanished">Platform ini tak mendukung IPv6</translation>
+ <translation>Platform ini tak mendukung IPv6</translation>
</message>
</context>
<context>
<name>QUndoGroup</name>
<message>
<source>Undo</source>
- <translation type="vanished">Batalkan</translation>
+ <translation>Batalkan</translation>
</message>
<message>
<source>Redo</source>
- <translation type="vanished">Jadi lagi</translation>
+ <translation>Jadi lagi</translation>
</message>
<message>
<source>Undo %1</source>
- <translation type="unfinished"></translation>
+ <translation>Batalkan %1</translation>
</message>
<message>
<source>Undo</source>
<comment>Default text for undo action</comment>
- <translation type="unfinished">Batalkan</translation>
+ <translation>Batalkan</translation>
</message>
<message>
<source>Redo %1</source>
- <translation type="unfinished"></translation>
+ <translation>Jadi lagi %1</translation>
</message>
<message>
<source>Redo</source>
<comment>Default text for redo action</comment>
- <translation type="unfinished">Jadi lagi</translation>
+ <translation>Jadi lagi</translation>
</message>
</context>
<context>
@@ -7600,29 +7602,29 @@ Role of an accessible object</extracomment>
<name>QUndoStack</name>
<message>
<source>Undo</source>
- <translation type="vanished">Batalkan</translation>
+ <translation>Batalkan</translation>
</message>
<message>
<source>Redo</source>
- <translation type="vanished">Jadi lagi</translation>
+ <translation>Jadi lagi</translation>
</message>
<message>
<source>Undo %1</source>
- <translation type="unfinished"></translation>
+ <translation>Batalkan %1</translation>
</message>
<message>
<source>Undo</source>
<comment>Default text for undo action</comment>
- <translation type="unfinished">Batalkan</translation>
+ <translation>Batalkan</translation>
</message>
<message>
<source>Redo %1</source>
- <translation type="unfinished"></translation>
+ <translation>Jadi lagi %1</translation>
</message>
<message>
<source>Redo</source>
<comment>Default text for redo action</comment>
- <translation type="unfinished">Jadi lagi</translation>
+ <translation>Jadi lagi</translation>
</message>
</context>
<context>
@@ -7673,297 +7675,297 @@ Role of an accessible object</extracomment>
</message>
<message>
<source>LRI Left-to-right isolate</source>
- <translation type="unfinished"></translation>
+ <translation>LRI Left-to-right isolate</translation>
</message>
<message>
<source>RLI Right-to-left isolate</source>
- <translation type="unfinished"></translation>
+ <translation>RLI Right-to-left isolate</translation>
</message>
<message>
<source>FSI First strong isolate</source>
- <translation type="unfinished"></translation>
+ <translation>FSI First strong isolate</translation>
</message>
<message>
<source>PDI Pop directional isolate</source>
- <translation type="unfinished"></translation>
+ <translation>PDI Pop directional isolate</translation>
</message>
</context>
<context>
<name>QWebFrame</name>
<message>
<source>Request cancelled</source>
- <translation type="vanished">Permintaan dibatalkan</translation>
+ <translation>Permintaan dibatalkan</translation>
</message>
<message>
<source>Request blocked</source>
- <translation type="vanished">Permintaan diblok</translation>
+ <translation>Permintaan diblok</translation>
</message>
<message>
<source>Cannot show URL</source>
- <translation type="vanished">Tak bisa menampilkan URL</translation>
+ <translation>Tak bisa menampilkan URL</translation>
</message>
<message>
<source>Frame load interruped by policy change</source>
- <translation type="vanished">Pemuatan frame diinterupsi oleh perubahan kebijakan</translation>
+ <translation>Pemuatan frame diinterupsi oleh perubahan kebijakan</translation>
</message>
<message>
<source>Cannot show mimetype</source>
- <translation type="vanished">Tak bisa menampilkan mimetype</translation>
+ <translation>Tak bisa menampilkan mimetype</translation>
</message>
<message>
<source>File does not exist</source>
- <translation type="vanished">File tak ada</translation>
+ <translation>File tak ada</translation>
</message>
</context>
<context>
<name>QWebPage</name>
<message>
<source>Bad HTTP request</source>
- <translation type="vanished">Permintaan HTTP buruk</translation>
+ <translation>Permintaan HTTP buruk</translation>
</message>
<message>
<source>Submit</source>
<comment>default label for Submit buttons in forms on web pages</comment>
- <translation type="vanished">Submit</translation>
+ <translation>Submit</translation>
</message>
<message>
<source>Submit</source>
<comment>Submit (input element) alt text for <input> elements with no alt, title, or value</comment>
- <translation type="vanished">Submit</translation>
+ <translation>Submit</translation>
</message>
<message>
<source>Reset</source>
<comment>default label for Reset buttons in forms on web pages</comment>
- <translation type="vanished">Reset</translation>
+ <translation>Reset</translation>
</message>
<message>
<source>This is a searchable index. Enter search keywords: </source>
<comment>text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index'</comment>
- <translation type="vanished">Ini adalah indeks yang dapat dicari. Masukkan kata kunci pencarian: </translation>
+ <translation>Ini adalah indeks yang dapat dicari. Masukkan kata kunci pencarian: </translation>
</message>
<message>
<source>Choose File</source>
<comment>title for file button used in HTML forms</comment>
- <translation type="vanished">Pilih File</translation>
+ <translation>Pilih File</translation>
</message>
<message>
<source>No file selected</source>
<comment>text to display in file button used in HTML forms when no file is selected</comment>
- <translation type="vanished">Tak ada file yang dipilih</translation>
+ <translation>Tak ada file yang dipilih</translation>
</message>
<message>
<source>Open in New Window</source>
<comment>Open in New Window context menu item</comment>
- <translation type="vanished">Buka di Window Baru</translation>
+ <translation>Buka di Window Baru</translation>
</message>
<message>
<source>Save Link...</source>
<comment>Download Linked File context menu item</comment>
- <translation type="vanished">Simpan Taut...</translation>
+ <translation>Simpan Taut...</translation>
</message>
<message>
<source>Copy Link</source>
<comment>Copy Link context menu item</comment>
- <translation type="vanished">Salin Taut</translation>
+ <translation>Salin Taut</translation>
</message>
<message>
<source>Open Image</source>
<comment>Open Image in New Window context menu item</comment>
- <translation type="vanished">Buka Citra</translation>
+ <translation>Buka Citra</translation>
</message>
<message>
<source>Save Image</source>
<comment>Download Image context menu item</comment>
- <translation type="vanished">Simpan Citra</translation>
+ <translation>Simpan Citra</translation>
</message>
<message>
<source>Copy Image</source>
<comment>Copy Link context menu item</comment>
- <translation type="vanished">Salin Citra</translation>
+ <translation>Salin Citra</translation>
</message>
<message>
<source>Open Frame</source>
<comment>Open Frame in New Window context menu item</comment>
- <translation type="vanished">Buka Frame</translation>
+ <translation>Buka Frame</translation>
</message>
<message>
<source>Copy</source>
<comment>Copy context menu item</comment>
- <translation type="vanished">Salin</translation>
+ <translation>Salin</translation>
</message>
<message>
<source>Go Back</source>
<comment>Back context menu item</comment>
- <translation type="vanished">Mundur</translation>
+ <translation>Mundur</translation>
</message>
<message>
<source>Go Forward</source>
<comment>Forward context menu item</comment>
- <translation type="vanished">Maju</translation>
+ <translation>Maju</translation>
</message>
<message>
<source>Stop</source>
<comment>Stop context menu item</comment>
- <translation type="vanished">Stop</translation>
+ <translation>Stop</translation>
</message>
<message>
<source>Reload</source>
<comment>Reload context menu item</comment>
- <translation type="vanished">Muat Ulang</translation>
+ <translation>Muat Ulang</translation>
</message>
<message>
<source>Cut</source>
<comment>Cut context menu item</comment>
- <translation type="vanished">Potong</translation>
+ <translation>Potong</translation>
</message>
<message>
<source>Paste</source>
<comment>Paste context menu item</comment>
- <translation type="vanished">Tempel</translation>
+ <translation>Tempel</translation>
</message>
<message>
<source>No Guesses Found</source>
<comment>No Guesses Found context menu item</comment>
- <translation type="vanished">Tebakan Tak Ditemukan</translation>
+ <translation>Tebakan Tak Ditemukan</translation>
</message>
<message>
<source>Ignore</source>
<comment>Ignore Spelling context menu item</comment>
- <translation type="vanished">Abaikan</translation>
+ <translation>Abaikan</translation>
</message>
<message>
<source>Add To Dictionary</source>
<comment>Learn Spelling context menu item</comment>
- <translation type="vanished">Tambahkan Ke Kamus</translation>
+ <translation>Tambahkan Ke Kamus</translation>
</message>
<message>
<source>Search The Web</source>
<comment>Search The Web context menu item</comment>
- <translation type="vanished">Cari Di Web</translation>
+ <translation>Cari Di Web</translation>
</message>
<message>
<source>Look Up In Dictionary</source>
<comment>Look Up in Dictionary context menu item</comment>
- <translation type="vanished">Lihat Di Kamus</translation>
+ <translation>Lihat Di Kamus</translation>
</message>
<message>
<source>Open Link</source>
<comment>Open Link context menu item</comment>
- <translation type="vanished">Buka Taut</translation>
+ <translation>Buka Taut</translation>
</message>
<message>
<source>Ignore</source>
<comment>Ignore Grammar context menu item</comment>
- <translation type="vanished">Abaikan</translation>
+ <translation>Abaikan</translation>
</message>
<message>
<source>Spelling</source>
<comment>Spelling and Grammar context sub-menu item</comment>
- <translation type="vanished">Ejaan</translation>
+ <translation>Ejaan</translation>
</message>
<message>
<source>Show Spelling and Grammar</source>
<comment>menu item title</comment>
- <translation type="vanished">Tampilkan Ejaan dan Tata Bahasa</translation>
+ <translation>Tampilkan Ejaan dan Tata Bahasa</translation>
</message>
<message>
<source>Hide Spelling and Grammar</source>
<comment>menu item title</comment>
- <translation type="vanished">Sembunyikan Ejaan dan Tata Bahasa</translation>
+ <translation>Sembunyikan Ejaan dan Tata Bahasa</translation>
</message>
<message>
<source>Check Spelling</source>
<comment>Check spelling context menu item</comment>
- <translation type="vanished">Periksa Ejaan</translation>
+ <translation>Periksa Ejaan</translation>
</message>
<message>
<source>Check Spelling While Typing</source>
<comment>Check spelling while typing context menu item</comment>
- <translation type="vanished">Periksa Ejaan Ketika Mengetik</translation>
+ <translation>Periksa Ejaan Ketika Mengetik</translation>
</message>
<message>
<source>Check Grammar With Spelling</source>
<comment>Check grammar with spelling context menu item</comment>
- <translation type="vanished">Periksa Tata Bahasa Ketika Mengetik</translation>
+ <translation>Periksa Tata Bahasa Ketika Mengetik</translation>
</message>
<message>
<source>Fonts</source>
<comment>Font context sub-menu item</comment>
- <translation type="vanished">Font</translation>
+ <translation>Font</translation>
</message>
<message>
<source>Bold</source>
<comment>Bold context menu item</comment>
- <translation type="vanished">Tebal</translation>
+ <translation>Tebal</translation>
</message>
<message>
<source>Italic</source>
<comment>Italic context menu item</comment>
- <translation type="vanished">Miring</translation>
+ <translation>Miring</translation>
</message>
<message>
<source>Underline</source>
<comment>Underline context menu item</comment>
- <translation type="vanished">Garis Bawah</translation>
+ <translation>Garis Bawah</translation>
</message>
<message>
<source>Outline</source>
<comment>Outline context menu item</comment>
- <translation type="vanished">Outline</translation>
+ <translation>Outline</translation>
</message>
<message>
<source>Direction</source>
<comment>Writing direction context sub-menu item</comment>
- <translation type="vanished">Arah</translation>
+ <translation>Arah</translation>
</message>
<message>
<source>Default</source>
<comment>Default writing direction context menu item</comment>
- <translation type="vanished">Bawaan</translation>
+ <translation>Bawaan</translation>
</message>
<message>
<source>LTR</source>
<comment>Left to Right context menu item</comment>
- <translation type="vanished">LTR</translation>
+ <translation>LTR</translation>
</message>
<message>
<source>RTL</source>
<comment>Right to Left context menu item</comment>
- <translation type="vanished">RTL</translation>
+ <translation>RTL</translation>
</message>
<message>
<source>Inspect</source>
<comment>Inspect Element context menu item</comment>
- <translation type="vanished">Periksa</translation>
+ <translation>Periksa</translation>
</message>
<message>
<source>No recent searches</source>
<comment>Label for only item in menu that appears when clicking on the search field image, when no searches have been performed</comment>
- <translation type="vanished">Tak ada pencarian terkini</translation>
+ <translation>Tak ada pencarian terkini</translation>
</message>
<message>
<source>Recent searches</source>
<comment>label for first item in the menu that appears when clicking on the search field image, used as embedded menu title</comment>
- <translation type="vanished">Pencarian terkini</translation>
+ <translation>Pencarian terkini</translation>
</message>
<message>
<source>Clear recent searches</source>
<comment>menu item in Recent Searches menu that empties menu's contents</comment>
- <translation type="vanished">Bersihkan pencarian terkini</translation>
+ <translation>Bersihkan pencarian terkini</translation>
</message>
<message>
<source>Unknown</source>
<comment>Unknown filesize FTP directory listing item</comment>
- <translation type="vanished">Tak Dikenal</translation>
+ <translation>Tak Dikenal</translation>
</message>
<message>
<source>%1 (%2x%3 pixels)</source>
<comment>Title string for images</comment>
- <translation type="vanished">%1 (%2x%3 piksel)</translation>
+ <translation>%1 (%2x%3 piksel)</translation>
</message>
<message>
<source>Web Inspector - %2</source>
- <translation type="vanished">Web Inspector - %2</translation>
+ <translation>Web Inspector - %2</translation>
</message>
</context>
<context>
@@ -7984,35 +7986,35 @@ Role of an accessible object</extracomment>
<name>QWidgetTextControl</name>
<message>
<source>&Undo</source>
- <translation type="unfinished">&Batalkan</translation>
+ <translation>&Batalkan</translation>
</message>
<message>
<source>&Redo</source>
- <translation type="unfinished">&Jadi Lagi</translation>
+ <translation>&Jadi Lagi</translation>
</message>
<message>
<source>Cu&t</source>
- <translation type="unfinished">Po&tong</translation>
+ <translation>Po&tong</translation>
</message>
<message>
<source>&Copy</source>
- <translation type="unfinished">&Salin</translation>
+ <translation>&Salin</translation>
</message>
<message>
<source>Copy &Link Location</source>
- <translation type="unfinished">Salin &Lokasi Taut</translation>
+ <translation>Salin &Lokasi Taut</translation>
</message>
<message>
<source>&Paste</source>
- <translation type="unfinished">Tem&pel</translation>
+ <translation>Tem&pel</translation>
</message>
<message>
<source>Delete</source>
- <translation type="unfinished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
<message>
<source>Select All</source>
- <translation type="unfinished">Pilih Semua</translation>
+ <translation>Pilih Semua</translation>
</message>
</context>
<context>
@@ -8021,11 +8023,13 @@ Role of an accessible object</extracomment>
<source>Qt cannot load the direct2d platform plugin because the Direct2D version on this system is too old. The minimum system requirement for this platform plugin is Windows 7 SP1 with Platform Update.
The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on this system is %5.%6.%7.%8.</source>
- <translation type="unfinished"></translation>
+ <translation type="unfinished">Qt tidak bisa memuat plugin platform direct2d karena versi Direct2D pada sistem ini terlalu tua. Persyaratan minimum sistem bagi plugin platform ini adalah Windows 7 SP1 dengan Pembaruan Platform.
+
+</translation>
</message>
<message>
<source>Cannot load direct2d platform plugin</source>
- <translation type="unfinished"></translation>
+ <translation>Tidak bisa memuat plugin platform direct2d</translation>
</message>
</context>
<context>
@@ -8048,7 +8052,7 @@ The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on th
</message>
<message>
<source>Quit</source>
- <translation type="vanished">Keluar</translation>
+ <translation>Keluar</translation>
</message>
<message>
<source>Help</source>
@@ -8083,55 +8087,55 @@ The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on th
<name>QWorkspace</name>
<message>
<source>&Restore</source>
- <translation type="vanished">&Kembalikan</translation>
+ <translation>&Kembalikan</translation>
</message>
<message>
<source>&Move</source>
- <translation type="vanished">&Pindahkan</translation>
+ <translation>&Pindahkan</translation>
</message>
<message>
<source>&Size</source>
- <translation type="vanished">&Ukuran</translation>
+ <translation>&Ukuran</translation>
</message>
<message>
<source>Mi&nimize</source>
- <translation type="vanished">Mi&nimalkan</translation>
+ <translation>Mi&nimalkan</translation>
</message>
<message>
<source>Ma&ximize</source>
- <translation type="vanished">Ma&ksimalkan</translation>
+ <translation>Ma&ksimalkan</translation>
</message>
<message>
<source>&Close</source>
- <translation type="vanished">Tutu&p</translation>
+ <translation>Tutu&p</translation>
</message>
<message>
<source>Stay on &Top</source>
- <translation type="vanished">&Tetap di Atas</translation>
+ <translation>&Tetap di Atas</translation>
</message>
<message>
<source>Sh&ade</source>
- <translation type="vanished">Berb&ayang</translation>
+ <translation>Berb&ayang</translation>
</message>
<message>
<source>%1 - [%2]</source>
- <translation type="vanished">%1 - [%2]</translation>
+ <translation>%1 - [%2]</translation>
</message>
<message>
<source>Minimize</source>
- <translation type="vanished">Minimalkan</translation>
+ <translation>Minimalkan</translation>
</message>
<message>
<source>Restore Down</source>
- <translation type="vanished">Kembali Turun</translation>
+ <translation>Kembali Turun</translation>
</message>
<message>
<source>Close</source>
- <translation type="vanished">Tutup</translation>
+ <translation>Tutup</translation>
</message>
<message>
<source>&Unshade</source>
- <translation type="vanished">Hap&us Bayang</translation>
+ <translation>Hap&us Bayang</translation>
</message>
</context>
<context>
@@ -8253,7 +8257,7 @@ The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on th
</message>
<message>
<source>Attribute redefined.</source>
- <translation type="vanished">Atribut didefinisikan ulang.</translation>
+ <translation>Atribut didefinisikan ulang.</translation>
</message>
<message>
<source>Unexpected character '%1' in public id literal.</source>
@@ -8373,656 +8377,656 @@ The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on th
</message>
<message>
<source>Attribute '%1' redefined.</source>
- <translation type="unfinished"></translation>
+ <translation>Atribut '%1' didefinisikan ulang.</translation>
</message>
</context>
<context>
<name>QtXmlPatterns</name>
<message>
<source>An %1-attribute with value %2 has already been declared.</source>
- <translation type="vanished">Suatu atribut %1 dengan nilai %2 telah dideklarasikan.</translation>
+ <translation>Suatu atribut %1 dengan nilai %2 telah dideklarasikan.</translation>
</message>
<message>
<source>An %1-attribute must have a valid %2 as value, which %3 isn't.</source>
- <translation type="vanished">Suatu atribut %1 mesti memiliki %2 yang valid sebagai nilai, sedangkan %3 tidak.</translation>
+ <translation>Suatu atribut %1 mesti memiliki %2 yang valid sebagai nilai, sedangkan %3 tidak.</translation>
</message>
<message>
<source>Network timeout.</source>
- <translation type="vanished">Habis waktu jaringan.</translation>
+ <translation>Habis waktu jaringan.</translation>
</message>
<message>
<source>Element %1 can't be serialized because it appears outside the document element.</source>
- <translation type="vanished">Elemen %1 tak dapat diserialisasi karena muncul di luar elemen dokumen.</translation>
+ <translation>Elemen %1 tak dapat diserialisasi karena muncul di luar elemen dokumen.</translation>
</message>
<message>
<source>Attribute %1 can't be serialized because it appears at the top level.</source>
- <translation type="vanished">Atribut %1 tak dapat diserialisasi karena muncul di level puncak.</translation>
+ <translation>Atribut %1 tak dapat diserialisasi karena muncul di level puncak.</translation>
</message>
<message>
<source>Year %1 is invalid because it begins with %2.</source>
- <translation type="vanished">Tahun %1 tak valid karena dimulai dengan %2.</translation>
+ <translation>Tahun %1 tak valid karena dimulai dengan %2.</translation>
</message>
<message>
<source>Day %1 is outside the range %2..%3.</source>
- <translation type="vanished">Tanggal %1 di luar jangkauan %2..%3.</translation>
+ <translation>Tanggal %1 di luar jangkauan %2..%3.</translation>
</message>
<message>
<source>Month %1 is outside the range %2..%3.</source>
- <translation type="vanished">Bulan %1 di luar jangkauan %2..%3.</translation>
+ <translation>Bulan %1 di luar jangkauan %2..%3.</translation>
</message>
<message>
<source>Overflow: Can't represent date %1.</source>
- <translation type="vanished">Overflow: Tak bisa merepresentasikan tanggal %1.</translation>
+ <translation>Overflow: Tak bisa merepresentasikan tanggal %1.</translation>
</message>
<message>
<source>Day %1 is invalid for month %2.</source>
- <translation type="vanished">Tanggal %1 tak valid bagi bulan %2.</translation>
+ <translation>Tanggal %1 tak valid bagi bulan %2.</translation>
</message>
<message>
<source>Time 24:%1:%2.%3 is invalid. Hour is 24, but minutes, seconds, and milliseconds are not all 0; </source>
- <translation type="vanished">Waktu 24:%1:%2.%3 tak valid. Jam 24, tapi menit, detik, dan milidetik semua bukan 0; </translation>
+ <translation>Waktu 24:%1:%2.%3 tak valid. Jam 24, tapi menit, detik, dan milidetik semua bukan 0; </translation>
</message>
<message>
<source>Time %1:%2:%3.%4 is invalid.</source>
- <translation type="vanished">Waktu %1:%2:%3.%4 tak valid.</translation>
+ <translation>Waktu %1:%2:%3.%4 tak valid.</translation>
</message>
<message>
<source>Overflow: Date can't be represented.</source>
- <translation type="vanished">Overflow: Tanggal tak bisa direpresentasikan.</translation>
+ <translation>Overflow: Tanggal tak bisa direpresentasikan.</translation>
</message>
<message>
<source>At least one component must be present.</source>
- <translation type="vanished">Paling tidak mesti ada satu komponen.</translation>
+ <translation>Paling tidak mesti ada satu komponen.</translation>
</message>
<message>
<source>At least one time component must appear after the %1-delimiter.</source>
- <translation type="vanished">Paling tidak satu komponen waktu mesti ada setelah delimiter %1.</translation>
+ <translation>Paling tidak satu komponen waktu mesti ada setelah delimiter %1.</translation>
</message>
<message>
<source>No operand in an integer division, %1, can be %2.</source>
- <translation type="vanished">Tidak ada operand dalam pembagian bilangan bulat, %1, bisa jadi %2.</translation>
+ <translation>Tidak ada operand dalam pembagian bilangan bulat, %1, bisa jadi %2.</translation>
</message>
<message>
<source>The first operand in an integer division, %1, cannot be infinity (%2).</source>
- <translation type="vanished">Operand pertama dalam pembagian bilangan bulat, %1, tak boleh tak hingga (%2).</translation>
+ <translation>Operand pertama dalam pembagian bilangan bulat, %1, tak boleh tak hingga (%2).</translation>
</message>
<message>
<source>The second operand in a division, %1, cannot be zero (%2).</source>
- <translation type="vanished">Operand kedua dalam suatu pembagian, %1, tak boleh nol (%2).</translation>
+ <translation>Operand kedua dalam suatu pembagian, %1, tak boleh nol (%2).</translation>
</message>
<message>
<source>%1 is not a valid value of type %2.</source>
- <translation type="vanished">%1 bukan nilai yang valid dari tipe %2.</translation>
+ <translation>%1 bukan nilai yang valid dari tipe %2.</translation>
</message>
<message>
<source>When casting to %1 from %2, the source value cannot be %3.</source>
- <translation type="vanished">Saat casting ke %1 dari %2, nilai sumber tak boleh %3.</translation>
+ <translation>Saat casting ke %1 dari %2, nilai sumber tak boleh %3.</translation>
</message>
<message>
<source>Integer division (%1) by zero (%2) is undefined.</source>
- <translation type="vanished">Pembagian bilangan bulat (%1) oleh nol (%2) tak terdefinisi.</translation>
+ <translation>Pembagian bilangan bulat (%1) oleh nol (%2) tak terdefinisi.</translation>
</message>
<message>
<source>Division (%1) by zero (%2) is undefined.</source>
- <translation type="vanished">Pembagian (%1) oleh nol (%2) tak terdefinisi.</translation>
+ <translation>Pembagian (%1) oleh nol (%2) tak terdefinisi.</translation>
</message>
<message>
<source>Modulus division (%1) by zero (%2) is undefined.</source>
- <translation type="vanished">Pembagian modulus (%1) oleh nol (%2) tak terdefinisi.</translation>
+ <translation>Pembagian modulus (%1) oleh nol (%2) tak terdefinisi.</translation>
</message>
<message>
<source>Dividing a value of type %1 by %2 (not-a-number) is not allowed.</source>
- <translation type="vanished">Membagi suatu nilai bertipe %1 dengan %2 (bukan sebuah bilangan) tak diijinkan.</translation>
+ <translation>Membagi suatu nilai bertipe %1 dengan %2 (bukan sebuah bilangan) tak diijinkan.</translation>
</message>
<message>
<source>Dividing a value of type %1 by %2 or %3 (plus or minus zero) is not allowed.</source>
- <translation type="vanished">Membagi suatu nilai bertipe %1 dengan %2 atau %3 (plus atau minus nol) tak diijinkan.</translation>
+ <translation>Membagi suatu nilai bertipe %1 dengan %2 atau %3 (plus atau minus nol) tak diijinkan.</translation>
</message>
<message>
<source>Multiplication of a value of type %1 by %2 or %3 (plus or minus infinity) is not allowed.</source>
- <translation type="vanished">Perkalian atas suatu nilai bertipe %1 dengan %2 atau %3 (plus atau minus tak hingga) tak diijinkan.</translation>
+ <translation>Perkalian atas suatu nilai bertipe %1 dengan %2 atau %3 (plus atau minus tak hingga) tak diijinkan.</translation>
</message>
<message>
<source>A value of type %1 cannot have an Effective Boolean Value.</source>
- <translation type="vanished">Suatu nilai bertipe %1 tak bisa memiliki Effective Boolean Value.</translation>
+ <translation>Suatu nilai bertipe %1 tak bisa memiliki Effective Boolean Value.</translation>
</message>
<message>
<source>Effective Boolean Value cannot be calculated for a sequence containing two or more atomic values.</source>
- <translation type="vanished">Effective Booelan Value tak bisa dihitung bagi urutan yang memuat dua atau lebih nilai atomik.</translation>
+ <translation>Effective Booelan Value tak bisa dihitung bagi urutan yang memuat dua atau lebih nilai atomik.</translation>
</message>
<message>
<source>Value %1 of type %2 exceeds maximum (%3).</source>
- <translation type="vanished">Nilai %1 bertipe %2 melebihi maksimum (%3).</translation>
+ <translation>Nilai %1 bertipe %2 melebihi maksimum (%3).</translation>
</message>
<message>
<source>Value %1 of type %2 is below minimum (%3).</source>
- <translation type="vanished">Nilai %1 bertipe %2 kurang dari minimum (%3).</translation>
+ <translation>Nilai %1 bertipe %2 kurang dari minimum (%3).</translation>
</message>
<message>
<source>A value of type %1 must contain an even number of digits. The value %2 does not.</source>
- <translation type="vanished">Sebuah nilai bertipe %1 mesti memuat suatu jumlah digit genap. Nilai %2 tidak.</translation>
+ <translation>Sebuah nilai bertipe %1 mesti memuat suatu jumlah digit genap. Nilai %2 tidak.</translation>
</message>
<message>
<source>%1 is not valid as a value of type %2.</source>
- <translation type="vanished">%1 tak valid sebagai sebuah nilai bertipe %2.</translation>
+ <translation>%1 tak valid sebagai sebuah nilai bertipe %2.</translation>
</message>
<message>
<source>Operator %1 cannot be used on type %2.</source>
- <translation type="vanished">Operator %1 tak dapat dipakai pada tipe %2.</translation>
+ <translation>Operator %1 tak dapat dipakai pada tipe %2.</translation>
</message>
<message>
<source>Operator %1 cannot be used on atomic values of type %2 and %3.</source>
- <translation type="vanished">Operator %1 tak dapat dipakai pada nilai atomik bertipe %2 dan %3.</translation>
+ <translation>Operator %1 tak dapat dipakai pada nilai atomik bertipe %2 dan %3.</translation>
</message>
<message>
<source>The namespace URI in the name for a computed attribute cannot be %1.</source>
- <translation type="vanished">URI namespace dalam nama bagi suatu atribut yang dihitung tak boleh %1.</translation>
+ <translation>URI namespace dalam nama bagi suatu atribut yang dihitung tak boleh %1.</translation>
</message>
<message>
<source>The name for a computed attribute cannot have the namespace URI %1 with the local name %2.</source>
- <translation type="vanished">Nama bagi atribut yang dihitung tak boleh memiliki URI namespace %1 dengan nama lokal %2.</translation>
+ <translation>Nama bagi atribut yang dihitung tak boleh memiliki URI namespace %1 dengan nama lokal %2.</translation>
</message>
<message>
<source>Type error in cast, expected %1, received %2.</source>
- <translation type="vanished">Kesalahan tipe dalam cast, diharapkan %1, diterima %2.</translation>
+ <translation>Kesalahan tipe dalam cast, diharapkan %1, diterima %2.</translation>
</message>
<message>
<source>When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed.</source>
- <translation type="vanished">Ketika casting ke %1 atau tipe turunannya, nilai sumber mesti bertipe sama, atau berupa literal string. Tipe %2 tak diijinkan.</translation>
+ <translation>Ketika casting ke %1 atau tipe turunannya, nilai sumber mesti bertipe sama, atau berupa literal string. Tipe %2 tak diijinkan.</translation>
</message>
<message>
<source>No casting is possible with %1 as the target type.</source>
- <translation type="vanished">Tak ada casting yang mungkin untuk tipe target %1.</translation>
+ <translation>Tak ada casting yang mungkin untuk tipe target %1.</translation>
</message>
<message>
<source>It is not possible to cast from %1 to %2.</source>
- <translation type="vanished">Tak mungkin cast dari %1 ke %2.</translation>
+ <translation>Tak mungkin cast dari %1 ke %2.</translation>
</message>
<message>
<source>Casting to %1 is not possible because it is an abstract type, and can therefore never be instantiated.</source>
- <translation type="vanished">Casting ke %1 tak mungkin karena itu adalah tipe abstrak, sehingga tak pernah bisa di-instantiasi.</translation>
+ <translation>Casting ke %1 tak mungkin karena itu adalah tipe abstrak, sehingga tak pernah bisa di-instantiasi.</translation>
</message>
<message>
<source>It's not possible to cast the value %1 of type %2 to %3</source>
- <translation type="vanished">Tak mungkin cast nilai %1 bertipe %2 ke %3</translation>
+ <translation>Tak mungkin cast nilai %1 bertipe %2 ke %3</translation>
</message>
<message>
<source>Failure when casting from %1 to %2: %3</source>
- <translation type="vanished">Kegagalan saat casting dari %1 ke %2:%3</translation>
+ <translation>Kegagalan saat casting dari %1 ke %2:%3</translation>
</message>
<message>
<source>A comment cannot contain %1</source>
- <translation type="vanished">Komentar tak bisa memuat %1</translation>
+ <translation>Komentar tak bisa memuat %1</translation>
</message>
<message>
<source>A comment cannot end with a %1.</source>
- <translation type="vanished">Komentar tak bisa diakhiri dengan %1.</translation>
+ <translation>Komentar tak bisa diakhiri dengan %1.</translation>
</message>
<message>
<source>No comparisons can be done involving the type %1.</source>
- <translation type="vanished">Tak ada perbandingan yang dapat dilakukan yang melibatkan tipe %1.</translation>
+ <translation>Tak ada perbandingan yang dapat dilakukan yang melibatkan tipe %1.</translation>
</message>
<message>
<source>Operator %1 is not available between atomic values of type %2 and %3.</source>
- <translation type="vanished">Operator %1 tak tersedia antara nilai atomik bertipa %2 dan %3.</translation>
+ <translation>Operator %1 tak tersedia antara nilai atomik bertipa %2 dan %3.</translation>
</message>
<message>
<source>An attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place.</source>
- <translation type="vanished">Sebuah node atribut tak bisa menjadi anak dari suatu node dokumen. Maka, atribut %1 tidak pada tempatnya.</translation>
+ <translation>Sebuah node atribut tak bisa menjadi anak dari suatu node dokumen. Maka, atribut %1 tidak pada tempatnya.</translation>
</message>
<message>
<source>A library module cannot be evaluated directly. It must be imported from a main module.</source>
- <translation type="vanished">Sebuah modul pustaka tak bisa dievaluasi secara langsung. Itu harus diimpor dari suatu modul utama.</translation>
+ <translation>Sebuah modul pustaka tak bisa dievaluasi secara langsung. Itu harus diimpor dari suatu modul utama.</translation>
</message>
<message>
<source>A value of type %1 cannot be a predicate. A predicate must have either a numeric type or an Effective Boolean Value type.</source>
- <translation type="vanished">Sebuah nilai bertipe %1 tak bisa berupa predikat. Suatu predikat mesti memiliki tipe numerik atau bertipe Effective Boolean Value.</translation>
+ <translation>Sebuah nilai bertipe %1 tak bisa berupa predikat. Suatu predikat mesti memiliki tipe numerik atau bertipe Effective Boolean Value.</translation>
</message>
<message>
<source>A positional predicate must evaluate to a single numeric value.</source>
- <translation type="vanished">Sebuah predikat posisional harus mengevaluasi ke suau nilai numerik tunggal.</translation>
+ <translation>Sebuah predikat posisional harus mengevaluasi ke suau nilai numerik tunggal.</translation>
</message>
<message>
<source>The target name in a processing instruction cannot be %1 in any combination of upper and lower case. Therefore, is %2 invalid.</source>
- <translation type="vanished">Nama target dalam sebuah instruksi pemrosesan tak bisa %1 dalam kombinasi huruf besar dan kecil. Maka %2 tak valid.</translation>
+ <translation>Nama target dalam sebuah instruksi pemrosesan tak bisa %1 dalam kombinasi huruf besar dan kecil. Maka %2 tak valid.</translation>
</message>
<message>
<source>%1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3.</source>
- <translation type="vanished">%1 bukan nama target yang valid dalam suatu instruksi pemrosesan. Itu harus berupa nilai %2, mis. %3.</translation>
+ <translation>%1 bukan nama target yang valid dalam suatu instruksi pemrosesan. Itu harus berupa nilai %2, mis. %3.</translation>
</message>
<message>
<source>The last step in a path must contain either nodes or atomic values. It cannot be a mixture between the two.</source>
- <translation type="vanished">Langkah terakhir dalam suatu path mesti memuat nilai node atau atomik. Itu tak bisa berupa campuran antara keduanya.</translation>
+ <translation>Langkah terakhir dalam suatu path mesti memuat nilai node atau atomik. Itu tak bisa berupa campuran antara keduanya.</translation>
</message>
<message>
<source>The data of a processing instruction cannot contain the string %1</source>
- <translation type="vanished">Data dari instruksi pemrosesan tak boleh memuat string %1</translation>
+ <translation>Data dari instruksi pemrosesan tak boleh memuat string %1</translation>
</message>
<message>
<source>No namespace binding exists for the prefix %1</source>
- <translation type="vanished">Tidak ada binding namespace bagi prefiks %1</translation>
+ <translation>Tidak ada binding namespace bagi prefiks %1</translation>
</message>
<message>
<source>No namespace binding exists for the prefix %1 in %2</source>
- <translation type="vanished">Tidak ada binding namespace bagi prefiks %1 dalam %2</translation>
+ <translation>Tidak ada binding namespace bagi prefiks %1 dalam %2</translation>
</message>
<message>
<source>%1 is an invalid %2</source>
- <translation type="vanished">%1 adalah %2 yang tak valid</translation>
+ <translation>%1 adalah %2 yang tak valid</translation>
</message>
<message numerus="yes">
<source>%1 takes at most %n argument(s). %2 is therefore invalid.</source>
- <translation type="vanished">
+ <translation>
<numerusform>%1 menerima paling banyak %n argumen. Maka %2 tak valid.</numerusform>
</translation>
</message>
<message numerus="yes">
<source>%1 requires at least %n argument(s). %2 is therefore invalid.</source>
- <translation type="vanished">
+ <translation>
<numerusform>%1 menerima paling sedikit %n argumen. Maka %2 tak valid.</numerusform>
</translation>
</message>
<message>
<source>The first argument to %1 cannot be of type %2. It must be a numeric type, xs:yearMonthDuration or xs:dayTimeDuration.</source>
- <translation type="vanished">Argumen pertama bagi %1 tak boleh bertipe %2. Itu harus berupa tipe numerik, xs:yearMonthDuration, atau xs:dayTimeDuration.</translation>
+ <translation>Argumen pertama bagi %1 tak boleh bertipe %2. Itu harus berupa tipe numerik, xs:yearMonthDuration, atau xs:dayTimeDuration.</translation>
</message>
<message>
<source>The first argument to %1 cannot be of type %2. It must be of type %3, %4, or %5.</source>
- <translation type="vanished">Argumen pertama bagi %1 tak boleh bertipe %2. Itu harus bertipe %3, %4, atau %5.</translation>
+ <translation>Argumen pertama bagi %1 tak boleh bertipe %2. Itu harus bertipe %3, %4, atau %5.</translation>
</message>
<message>
<source>The second argument to %1 cannot be of type %2. It must be of type %3, %4, or %5.</source>
- <translation type="vanished">Argumen kedua bagi %1 tak boleh bertipe %2. Itu harus bertipe %3, %4, atau %5.</translation>
+ <translation>Argumen kedua bagi %1 tak boleh bertipe %2. Itu harus bertipe %3, %4, atau %5.</translation>
</message>
<message>
<source>%1 is not a valid XML 1.0 character.</source>
- <translation type="vanished">%1 bukan karakter XML 1.0 yang valid.</translation>
+ <translation>%1 bukan karakter XML 1.0 yang valid.</translation>
</message>
<message>
<source>The first argument to %1 cannot be of type %2.</source>
- <translation type="vanished">Argumen pertama ke %1 tak boleh bertipe %2.</translation>
+ <translation>Argumen pertama ke %1 tak boleh bertipe %2.</translation>
</message>
<message>
<source>If both values have zone offsets, they must have the same zone offset. %1 and %2 are not the same.</source>
- <translation type="vanished">Bila kedua nilai memiliki ofset zone, mereka mesti memiliki ofset zone yang sama. %1 dan %2 tak sama.</translation>
+ <translation>Bila kedua nilai memiliki ofset zone, mereka mesti memiliki ofset zone yang sama. %1 dan %2 tak sama.</translation>
</message>
<message>
<source>%1 was called.</source>
- <translation type="vanished">%1 dipanggil.</translation>
+ <translation>%1 dipanggil.</translation>
</message>
<message>
<source>%1 must be followed by %2 or %3, not at the end of the replacement string.</source>
- <translation type="vanished">%1 mesti diikuti oleh %2 atau %3, bukan di akhir string pengganti.</translation>
+ <translation>%1 mesti diikuti oleh %2 atau %3, bukan di akhir string pengganti.</translation>
</message>
<message>
<source>In the replacement string, %1 must be followed by at least one digit when not escaped.</source>
- <translation type="vanished">Dalam string pengganti, %1 mesti diikuti oleh paling tidak satu digit ketika tidak di-escape.</translation>
+ <translation>Dalam string pengganti, %1 mesti diikuti oleh paling tidak satu digit ketika tidak di-escape.</translation>
</message>
<message>
<source>In the replacement string, %1 can only be used to escape itself or %2, not %3</source>
- <translation type="vanished">Dalam string pengganti, %1 hanya dapat dipakai untuk meng-escape dirinya sendiri atau %2, bukan %3</translation>
+ <translation>Dalam string pengganti, %1 hanya dapat dipakai untuk meng-escape dirinya sendiri atau %2, bukan %3</translation>
</message>
<message>
<source>%1 matches newline characters</source>
- <translation type="vanished">%1 cocok dengan karakter baris baru</translation>
+ <translation>%1 cocok dengan karakter baris baru</translation>
</message>
<message>
<source>%1 and %2 match the start and end of a line.</source>
- <translation type="vanished">%1 dan %2 cocok dengan awal dan akhir dari suatu baris.</translation>
+ <translation>%1 dan %2 cocok dengan awal dan akhir dari suatu baris.</translation>
</message>
<message>
<source>Matches are case insensitive</source>
- <translation type="vanished">Kecocokan peka huruf besar kecil</translation>
+ <translation>Kecocokan peka huruf besar kecil</translation>
</message>
<message>
<source>Whitespace characters are removed, except when they appear in character classes</source>
- <translation type="vanished">Karakter whitespace dihapus, kecuali ketika muncul dalam kelas karakter</translation>
+ <translation>Karakter whitespace dihapus, kecuali ketika muncul dalam kelas karakter</translation>
</message>
<message>
<source>%1 is an invalid regular expression pattern: %2</source>
- <translation type="vanished">%1 adalah pola ekspresi reguler yang tak valid: %2</translation>
+ <translation>%1 adalah pola ekspresi reguler yang tak valid: %2</translation>
</message>
<message>
<source>%1 is an invalid flag for regular expressions. Valid flags are:</source>
- <translation type="vanished">%1 adalah flag yang tak valid bagi ekspres reguler. Flag yang valid adalah:</translation>
+ <translation>%1 adalah flag yang tak valid bagi ekspres reguler. Flag yang valid adalah:</translation>
</message>
<message>
<source>If the first argument is the empty sequence or a zero-length string (no namespace), a prefix cannot be specified. Prefix %1 was specified.</source>
- <translation type="vanished">Bila argumen pertama adalah urutan kosong atau string panjang nol (tanpa namespace), suatu prefiks tak dapat dinyatakan. Prefiks %1 telah dinyatakan.</translation>
+ <translation>Bila argumen pertama adalah urutan kosong atau string panjang nol (tanpa namespace), suatu prefiks tak dapat dinyatakan. Prefiks %1 telah dinyatakan.</translation>
</message>
<message>
<source>It will not be possible to retrieve %1.</source>
- <translation type="vanished">Tak akan mungkin mengambil %1.</translation>
+ <translation>Tak akan mungkin mengambil %1.</translation>
</message>
<message>
<source>The root node of the second argument to function %1 must be a document node. %2 is not a document node.</source>
- <translation type="vanished">Node akar dari argumen kedia ke fungsi %1 mesti berupa suatu node dokumen. %2 bukan node dokumen.</translation>
+ <translation>Node akar dari argumen kedia ke fungsi %1 mesti berupa suatu node dokumen. %2 bukan node dokumen.</translation>
</message>
<message>
<source>The default collection is undefined</source>
- <translation type="vanished">Koleksi baku tak didefinisikan</translation>
+ <translation>Koleksi baku tak didefinisikan</translation>
</message>
<message>
<source>%1 cannot be retrieved</source>
- <translation type="vanished">%1 tak dapat diambil</translation>
+ <translation>%1 tak dapat diambil</translation>
</message>
<message>
<source>The normalization form %1 is unsupported. The supported forms are %2, %3, %4, and %5, and none, i.e. the empty string (no normalization).</source>
- <translation type="vanished">Bentuk normalisasi %1 tak didukung. Bentuk yang didukung adalah %2, %3, %4, dan %5, serta nihil, yaitu string kosong (tanpa normalisasi).</translation>
+ <translation>Bentuk normalisasi %1 tak didukung. Bentuk yang didukung adalah %2, %3, %4, dan %5, serta nihil, yaitu string kosong (tanpa normalisasi).</translation>
</message>
<message>
<source>A zone offset must be in the range %1..%2 inclusive. %3 is out of range.</source>
- <translation type="vanished">Ofset zone mesti dalam jangkauan %1..%2. %3 di luar jangkauan.</translation>
+ <translation>Ofset zone mesti dalam jangkauan %1..%2. %3 di luar jangkauan.</translation>
</message>
<message>
<source>%1 is not a whole number of minutes.</source>
- <translation type="vanished">%1 bukan angka menit yang bulat.</translation>
+ <translation>%1 bukan angka menit yang bulat.</translation>
</message>
<message>
<source>Required cardinality is %1; got cardinality %2.</source>
- <translation type="vanished">Kardinalitas yang diperlukan adalah %1; kardinalitas yang didapat %2.</translation>
+ <translation>Kardinalitas yang diperlukan adalah %1; kardinalitas yang didapat %2.</translation>
</message>
<message>
<source>The item %1 did not match the required type %2.</source>
- <translation type="vanished">Butir %1 tak cocok dengan tipe %2 yang diperlukan.</translation>
+ <translation>Butir %1 tak cocok dengan tipe %2 yang diperlukan.</translation>
</message>
<message>
<source>%1 is an unknown schema type.</source>
- <translation type="vanished">%1 adalah tipe skema yang tak dikenal.</translation>
+ <translation>%1 adalah tipe skema yang tak dikenal.</translation>
</message>
<message>
<source>Only one %1 declaration can occur in the query prolog.</source>
- <translation type="vanished">Hanya satu deklarasi %1 yang dapat terjadi dalam prolog query.</translation>
+ <translation>Hanya satu deklarasi %1 yang dapat terjadi dalam prolog query.</translation>
</message>
<message>
<source>The initialization of variable %1 depends on itself</source>
- <translation type="vanished">Inisialisasi variabel %1 bergantung kepada dirinya sendiri</translation>
+ <translation>Inisialisasi variabel %1 bergantung kepada dirinya sendiri</translation>
</message>
<message>
<source>No variable by name %1 exists</source>
- <translation type="vanished">Tak ada variabel bernama %1</translation>
+ <translation>Tak ada variabel bernama %1</translation>
</message>
<message>
<source>The variable %1 is unused</source>
- <translation type="vanished">Variabe %1 tak dipakai</translation>
+ <translation>Variabe %1 tak dipakai</translation>
</message>
<message>
<source>Version %1 is not supported. The supported XQuery version is 1.0.</source>
- <translation type="vanished">Versi %1 tak didukung. Versi XQuery yang didukung adalah 1.0.</translation>
+ <translation>Versi %1 tak didukung. Versi XQuery yang didukung adalah 1.0.</translation>
</message>
<message>
<source>The encoding %1 is invalid. It must contain Latin characters only, must not contain whitespace, and must match the regular expression %2.</source>
- <translation type="vanished">Pengkodean %1 tak valid. Itu mesti memuat hanya karakter Latin, tak boleh memuat whitespace, dan mesti cocok dengan ekspresi regular %2.</translation>
+ <translation>Pengkodean %1 tak valid. Itu mesti memuat hanya karakter Latin, tak boleh memuat whitespace, dan mesti cocok dengan ekspresi regular %2.</translation>
</message>
<message>
<source>No function with signature %1 is available</source>
- <translation type="vanished">Tak ada fungsi dengan tanda tangan %1 yang tersedia</translation>
+ <translation>Tak ada fungsi dengan tanda tangan %1 yang tersedia</translation>
</message>
<message>
<source>A default namespace declaration must occur before function, variable, and option declarations.</source>
- <translation type="vanished">Deklarasi namespace baku mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
+ <translation>Deklarasi namespace baku mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
</message>
<message>
<source>Namespace declarations must occur before function, variable, and option declarations.</source>
- <translation type="vanished">Deklarasi namespace mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
+ <translation>Deklarasi namespace mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
</message>
<message>
<source>Module imports must occur before function, variable, and option declarations.</source>
- <translation type="vanished">Impor modul mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
+ <translation>Impor modul mesti terjadi sebelum deklarasi fungsi, variabel, dan opsi.</translation>
</message>
<message>
<source>It is not possible to redeclare prefix %1.</source>
- <translation type="vanished">Tak mungkin mendeklarasi ulang prefiks %1.</translation>
+ <translation>Tak mungkin mendeklarasi ulang prefiks %1.</translation>
</message>
<message>
<source>Only the prefix %1 can be declared to bind the namespace %2. By default, it is already bound to the prefix %1.</source>
- <translation type="vanished">Hanya prefiks %1 dapat dideklarasikan untuk bind namespace %2. Secara baku, ia telah di-bind ke prefix %1.</translation>
+ <translation>Hanya prefiks %1 dapat dideklarasikan untuk bind namespace %2. Secara baku, ia telah di-bind ke prefix %1.</translation>
</message>
<message>
<source>Prefix %1 is already declared in the prolog.</source>
- <translation type="vanished">Prefiks %1 telah dideklarasikan dalam prolog.</translation>
+ <translation>Prefiks %1 telah dideklarasikan dalam prolog.</translation>
</message>
<message>
<source>The name of an option must have a prefix. There is no default namespace for options.</source>
- <translation type="vanished">Nama dari suatu opsi mesti memiliki prefiks. Tak ada namespace baku bagi opsi.</translation>
+ <translation>Nama dari suatu opsi mesti memiliki prefiks. Tak ada namespace baku bagi opsi.</translation>
</message>
<message>
<source>The Schema Import feature is not supported, and therefore %1 declarations cannot occur.</source>
- <translation type="vanished">Fitur Impor Skema tak didukung, sehingga deklarasi %1 tak bisa muncul.</translation>
+ <translation>Fitur Impor Skema tak didukung, sehingga deklarasi %1 tak bisa muncul.</translation>
</message>
<message>
<source>The target namespace of a %1 cannot be empty.</source>
- <translation type="vanished">Namespace tujuan dari %1 tak boleh kosong.</translation>
+ <translation>Namespace tujuan dari %1 tak boleh kosong.</translation>
</message>
<message>
<source>The module import feature is not supported</source>
- <translation type="vanished">Fitur impor modul tak didukung</translation>
+ <translation>Fitur impor modul tak didukung</translation>
</message>
<message>
<source>A variable by name %1 has already been declared in the prolog.</source>
- <translation type="vanished">Variabel bernama %1 telah dideklarasikan dalam prolog.</translation>
+ <translation>Variabel bernama %1 telah dideklarasikan dalam prolog.</translation>
</message>
<message>
<source>No value is available for the external variable by name %1.</source>
- <translation type="vanished">Tak ada nilai yang tersedia bagi variabel eksternal berdasarkan nama %1.</translation>
+ <translation>Tak ada nilai yang tersedia bagi variabel eksternal berdasarkan nama %1.</translation>
</message>
<message>
<source>The namespace for a user defined function cannot be empty (try the predefined prefix %1 which exists for cases like this)</source>
- <translation type="vanished">Namespace bagi fungsi yang didefinisikan oleh pengguna tak boleh kosong (coba prefiks terpradefinisi %1 yang ada untuk kasus-kasus seperti ini)</translation>
+ <translation>Namespace bagi fungsi yang didefinisikan oleh pengguna tak boleh kosong (coba prefiks terpradefinisi %1 yang ada untuk kasus-kasus seperti ini)</translation>
</message>
<message>
<source>The namespace %1 is reserved; therefore user defined functions may not use it. Try the predefined prefix %2, which exists for these cases.</source>
- <translation type="vanished">Namespace %1 dicadangkan; maka fungsi yang didefinisikan oleh pengguna tak boleh memakainya. Cobalah prefiks terpradefinisi %2, yang ada untuk kasus-kasus tersebut.</translation>
+ <translation>Namespace %1 dicadangkan; maka fungsi yang didefinisikan oleh pengguna tak boleh memakainya. Cobalah prefiks terpradefinisi %2, yang ada untuk kasus-kasus tersebut.</translation>
</message>
<message>
<source>The namespace of a user defined function in a library module must be equivalent to the module namespace. In other words, it should be %1 instead of %2</source>
- <translation type="vanished">Namespace dari suatu fungsi yang didefinisikan oleh pengguna dalam sebuah modul pustaka mesti ekuivalen dengan namespace modul. Dengan kata lain, itu mesti %1 dan bukan %2</translation>
+ <translation>Namespace dari suatu fungsi yang didefinisikan oleh pengguna dalam sebuah modul pustaka mesti ekuivalen dengan namespace modul. Dengan kata lain, itu mesti %1 dan bukan %2</translation>
</message>
<message>
<source>A function already exists with the signature %1.</source>
- <translation type="vanished">Telah ada fungsi dengan tanda tangan %1.</translation>
+ <translation>Telah ada fungsi dengan tanda tangan %1.</translation>
</message>
<message>
<source>No external functions are supported. All supported functions can be used directly, without first declaring them as external</source>
- <translation type="vanished">Tak ada fungsi eksternal yang didukung. Semua fungsi yang didukung dapat langsung dipakai, tanpa perlu mendeklarasikan mereka sebelumnya sebagai eksternal</translation>
+ <translation>Tak ada fungsi eksternal yang didukung. Semua fungsi yang didukung dapat langsung dipakai, tanpa perlu mendeklarasikan mereka sebelumnya sebagai eksternal</translation>
</message>
<message>
<source>An argument by name %1 has already been declared. Every argument name must be unique.</source>
- <translation type="vanished">Sebuah argumen bernama %1 telah dideklarasikan. Setiap nama argumen mesti unik.</translation>
+ <translation>Sebuah argumen bernama %1 telah dideklarasikan. Setiap nama argumen mesti unik.</translation>
</message>
<message>
<source>The name of a variable bound in a for-expression must be different from the positional variable. Hence, the two variables named %1 collide.</source>
- <translation type="vanished">Nama dari suatu variabel yang di-bind bagi ekspresi-for mesti berbeda dengan variable posisional. Maka, dua variabel bernam %1 bertabrakan.</translation>
+ <translation>Nama dari suatu variabel yang di-bind bagi ekspresi-for mesti berbeda dengan variable posisional. Maka, dua variabel bernam %1 bertabrakan.</translation>
</message>
<message>
<source>The Schema Validation Feature is not supported. Hence, %1-expressions may not be used.</source>
- <translation type="vanished">Fitur Validasi Skema tak didukung. Maka ekspresi %1 tak boleh dipakai.</translation>
+ <translation>Fitur Validasi Skema tak didukung. Maka ekspresi %1 tak boleh dipakai.</translation>
</message>
<message>
<source>None of the pragma expressions are supported. Therefore, a fallback expression must be present</source>
- <translation type="vanished">Tak satupun dari ekspresi pragman didukung. Maka, ekspresi fallback mesti ada</translation>
+ <translation>Tak satupun dari ekspresi pragman didukung. Maka, ekspresi fallback mesti ada</translation>
</message>
<message>
<source>The %1-axis is unsupported in XQuery</source>
- <translation type="vanished">Sumbu %1 tak didukung dalam XQuery</translation>
+ <translation>Sumbu %1 tak didukung dalam XQuery</translation>
</message>
<message>
<source>%1 is not a valid numeric literal.</source>
- <translation type="vanished">%1 bukan literal numerik yang valid.</translation>
+ <translation>%1 bukan literal numerik yang valid.</translation>
</message>
<message>
<source>No function by name %1 is available.</source>
- <translation type="vanished">Tak ada fungsi dengan nama %1 yang tersedia.</translation>
+ <translation>Tak ada fungsi dengan nama %1 yang tersedia.</translation>
</message>
<message>
<source>The namespace URI cannot be the empty string when binding to a prefix, %1.</source>
- <translation type="vanished">URI namespace tak boleh berupa string kosong ketika mem-bind ke suatu prefiks, %1.</translation>
+ <translation>URI namespace tak boleh berupa string kosong ketika mem-bind ke suatu prefiks, %1.</translation>
</message>
<message>
<source>%1 is an invalid namespace URI.</source>
- <translation type="vanished">%1 adalah URI namespace yang tak valid.</translation>
+ <translation>%1 adalah URI namespace yang tak valid.</translation>
</message>
<message>
<source>It is not possible to bind to the prefix %1</source>
- <translation type="vanished">Tak mungkin bind ke prefiks %1</translation>
+ <translation>Tak mungkin bind ke prefiks %1</translation>
</message>
<message>
<source>Namespace %1 can only be bound to %2 (and it is, in either case, pre-declared).</source>
- <translation type="vanished">Namespace %1 hanya dapat di-bind ke %2 (dan itu, pada kasus manapun, di pradeklarasikan).</translation>
+ <translation>Namespace %1 hanya dapat di-bind ke %2 (dan itu, pada kasus manapun, di pradeklarasikan).</translation>
</message>
<message>
<source>Prefix %1 can only be bound to %2 (and it is, in either case, pre-declared).</source>
- <translation type="vanished">Prefiks %1 hanya dapat di-bind ke %2 (dan itu, pada kasus manapun, di pradeklarasikan).</translation>
+ <translation>Prefiks %1 hanya dapat di-bind ke %2 (dan itu, pada kasus manapun, di pradeklarasikan).</translation>
</message>
<message>
<source>Two namespace declaration attributes have the same name: %1.</source>
- <translation type="vanished">Dua atribut deklarasi namespace memiliki nama yang sama: %1.</translation>
+ <translation>Dua atribut deklarasi namespace memiliki nama yang sama: %1.</translation>
</message>
<message>
<source>The namespace URI must be a constant and cannot use enclosed expressions.</source>
- <translation type="vanished">URI namespace mesti berupa konstanta dan tak boleh memakai ekspresi yang di-enclose.</translation>
+ <translation>URI namespace mesti berupa konstanta dan tak boleh memakai ekspresi yang di-enclose.</translation>
</message>
<message>
<source>An attribute by name %1 has already appeared on this element.</source>
- <translation type="vanished">Sebuah atribut bernama %1 telah muncul pada elemen ini.</translation>
+ <translation>Sebuah atribut bernama %1 telah muncul pada elemen ini.</translation>
</message>
<message>
<source>A direct element constructor is not well-formed. %1 is ended with %2.</source>
- <translation type="vanished">Susunan sebuah konstruktor elemen langsung tidak baik. %1 diakhiri dengan %2.</translation>
+ <translation>Susunan sebuah konstruktor elemen langsung tidak baik. %1 diakhiri dengan %2.</translation>
</message>
<message>
<source>The name %1 does not refer to any schema type.</source>
- <translation type="vanished">Nama %1 tak mengacu ke tipe skema apapun.</translation>
+ <translation>Nama %1 tak mengacu ke tipe skema apapun.</translation>
</message>
<message>
<source>%1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works.</source>
- <translation type="vanished">%1 adahal suatu tipe kompleks. Casting ke tipe kompleks tidak mungkin. Namun casting ke tipe atomik seperti %2 bisa.</translation>
+ <translation>%1 adahal suatu tipe kompleks. Casting ke tipe kompleks tidak mungkin. Namun casting ke tipe atomik seperti %2 bisa.</translation>
</message>
<message>
<source>%1 is not an atomic type. Casting is only possible to atomic types.</source>
- <translation type="vanished">%1 bukan tipe atomik. Casting hanya mungkin bagi tipe atomik.</translation>
+ <translation>%1 bukan tipe atomik. Casting hanya mungkin bagi tipe atomik.</translation>
</message>
<message>
<source>%1 is not a valid name for a processing-instruction. Therefore this name test will never match.</source>
- <translation type="vanished">%1 bukan nama yang valid bagi sebuah instruksi pemrosesan. Maka uji nama ini tak akan pernah cocok.</translation>
+ <translation>%1 bukan nama yang valid bagi sebuah instruksi pemrosesan. Maka uji nama ini tak akan pernah cocok.</translation>
</message>
<message>
<source>%1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported.</source>
- <translation type="vanished">%1 tak di dalam deklarasi atribu in-scope. Perhatikan bahwa fitur impor skema tak didukung.</translation>
+ <translation>%1 tak di dalam deklarasi atribu in-scope. Perhatikan bahwa fitur impor skema tak didukung.</translation>
</message>
<message>
<source>The name of an extension expression must be in a namespace.</source>
- <translation type="vanished">Nama dari ekspresi ekstensi mesti dalam suatu namespace.</translation>
+ <translation>Nama dari ekspresi ekstensi mesti dalam suatu namespace.</translation>
</message>
<message>
<source>empty</source>
- <translation type="vanished">kosong</translation>
+ <translation>kosong</translation>
</message>
<message>
<source>zero or one</source>
- <translation type="vanished">nol atau satu</translation>
+ <translation>nol atau satu</translation>
</message>
<message>
<source>exactly one</source>
- <translation type="vanished">tepat satu</translation>
+ <translation>tepat satu</translation>
</message>
<message>
<source>one or more</source>
- <translation type="vanished">satu atau lebih</translation>
+ <translation>satu atau lebih</translation>
</message>
<message>
<source>zero or more</source>
- <translation type="vanished">nol atau lebih</translation>
+ <translation>nol atau lebih</translation>
</message>
<message>
<source>Required type is %1, but %2 was found.</source>
- <translation type="vanished">Tipe yang diperlukan adalah %1, tapi yang ditemukan %2.</translation>
+ <translation>Tipe yang diperlukan adalah %1, tapi yang ditemukan %2.</translation>
</message>
<message>
<source>Promoting %1 to %2 may cause loss of precision.</source>
- <translation type="vanished">Mempromosikan %1 ke %2 dapat menyebabkan kehilangan presisi.</translation>
+ <translation>Mempromosikan %1 ke %2 dapat menyebabkan kehilangan presisi.</translation>
</message>
<message>
<source>The focus is undefined.</source>
- <translation type="vanished">Fokus tak terdefinisi.</translation>
+ <translation>Fokus tak terdefinisi.</translation>
</message>
<message>
<source>It's not possible to add attributes after any other kind of node.</source>
- <translation type="vanished">Tak mungkin menambah atribut setelah sebarang jenis node lain.</translation>
+ <translation>Tak mungkin menambah atribut setelah sebarang jenis node lain.</translation>
</message>
<message>
<source>An attribute by name %1 has already been created.</source>
- <translation type="vanished">Sebuah atribut bernama %1 telah dibuat.</translation>
+ <translation>Sebuah atribut bernama %1 telah dibuat.</translation>
</message>
<message>
<source>Only the Unicode Codepoint Collation is supported(%1). %2 is unsupported.</source>
- <translation type="vanished">Hanya Unicode Codepoint Collation yang didukung(%1). %2 tak didukung.</translation>
+ <translation>Hanya Unicode Codepoint Collation yang didukung(%1). %2 tak didukung.</translation>
</message>
</context>
<context>
<name>VolumeSlider</name>
<message>
<source>Muted</source>
- <translation type="vanished">Hening</translation>
+ <translation>Hening</translation>
</message>
<message>
<source>Volume: %1%</source>
- <translation type="vanished">Volume: %1%</translation>
+ <translation>Volume: %1%</translation>
</message>
</context>
<context>
<name>WebCore::PlatformScrollbar</name>
<message>
<source>Scroll here</source>
- <translation type="vanished">Gulung ke sini</translation>
+ <translation>Gulung ke sini</translation>
</message>
<message>
<source>Left edge</source>
- <translation type="vanished">Tepi kiri</translation>
+ <translation>Tepi kiri</translation>
</message>
<message>
<source>Top</source>
- <translation type="vanished">Puncak</translation>
+ <translation>Puncak</translation>
</message>
<message>
<source>Right edge</source>
- <translation type="vanished">Tepi kanan</translation>
+ <translation>Tepi kanan</translation>
</message>
<message>
<source>Bottom</source>
- <translation type="vanished">Dasar</translation>
+ <translation>Dasar</translation>
</message>
<message>
<source>Page left</source>
- <translation type="vanished">Halaman kiri</translation>
+ <translation>Halaman kiri</translation>
</message>
<message>
<source>Page up</source>
- <translation type="vanished">Halaman naik</translation>
+ <translation>Halaman naik</translation>
</message>
<message>
<source>Page right</source>
- <translation type="vanished">Halaman kanan</translation>
+ <translation>Halaman kanan</translation>
</message>
<message>
<source>Page down</source>
- <translation type="vanished">Halaman turun</translation>
+ <translation>Halaman turun</translation>
</message>
<message>
<source>Scroll left</source>
- <translation type="vanished">Gulung kiri</translation>
+ <translation>Gulung kiri</translation>
</message>
<message>
<source>Scroll up</source>
- <translation type="vanished">Gulung atas</translation>
+ <translation>Gulung atas</translation>
</message>
<message>
<source>Scroll right</source>
- <translation type="vanished">Gulung kanan</translation>
+ <translation>Gulung kanan</translation>
</message>
<message>
<source>Scroll down</source>
- <translation type="vanished">Gulung bawah</translation>
+ <translation>Gulung bawah</translation>
</message>
</context>
</TS>
diff --git a/src/VBox/Frontends/VirtualBox/src/VBoxAboutDlg.cpp b/src/VBox/Frontends/VirtualBox/src/VBoxAboutDlg.cpp
index a3ba859..38c9f8b 100644
--- a/src/VBox/Frontends/VirtualBox/src/VBoxAboutDlg.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/VBoxAboutDlg.cpp
@@ -127,7 +127,7 @@ void VBoxAboutDlg::prepare()
const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
const double dRatio = (double)iIconMetric / 32;
const QIcon icon = UIIconPool::iconSet(strPath);
- m_size = icon.availableSizes().first();
+ m_size = icon.availableSizes().value(0, QSize(640, 480));
m_size *= dRatio;
m_pixmap = icon.pixmap(m_size);
diff --git a/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp b/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp
index 752c7c5..d8f9d31 100644
--- a/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp
@@ -416,7 +416,7 @@ void UIChooserPaneDelegate::fetchPixmapInfo(const QModelIndex &index, QPixmap &p
{
/* For global ID we return static pixmap/size: */
const QIcon icon = UIIconPool::iconSet(":/edataglobal_32px.png");
- pixmapSize = icon.availableSizes().first();
+ pixmapSize = icon.availableSizes().value(0, QSize(32, 32));
pixmap = icon.pixmap(pixmapSize);
}
}
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
index 9fca6aa..3aa79d7 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.cpp
@@ -25,7 +25,8 @@
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
-/* Extension-pack definitions: */
+/* File name definitions: */
+const char* UIDefs::GUI_GuestAdditionsName = "VBoxGuestAdditions";
const char* UIDefs::GUI_ExtPackName = "Oracle VM VirtualBox Extension Pack";
/* File extensions definitions: */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
index 15d1d8f..2f00d7d 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDefs.h
@@ -79,7 +79,8 @@ namespace UIDefs
FormatSize_RoundUp
};
- /* Extension-pack declarations: */
+ /* File name declarations: */
+ extern const char* GUI_GuestAdditionsName;
extern const char* GUI_ExtPackName;
/* File extensions declarations: */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
index 4f96de8..f378a4d 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.cpp
@@ -354,6 +354,23 @@ bool UIDesktopWidgetWatchdog::isFakeScreenDetected() const
}
#endif /* VBOX_WS_X11 */
+double UIDesktopWidgetWatchdog::devicePixelRatio(int iHostScreenIndex)
+{
+ /* First, we should check whether the screen is valid: */
+ QScreen *pScreen = iHostScreenIndex == -1
+ ? QGuiApplication::primaryScreen()
+ : QGuiApplication::screens().value(iHostScreenIndex);
+ AssertPtrReturn(pScreen, 1.0);
+ /* Then acquire device-pixel-ratio: */
+ return pScreen->devicePixelRatio();
+}
+
+double UIDesktopWidgetWatchdog::devicePixelRatio(QWidget *pWidget)
+{
+ /* Redirect call to wrapper above: */
+ return devicePixelRatio(screenNumber(pWidget));
+}
+
void UIDesktopWidgetWatchdog::sltHostScreenAdded(QScreen *pHostScreen)
{
// printf("UIDesktopWidgetWatchdog::sltHostScreenAdded(%d)\n", screenCount());
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
index 24ca77c..1915c53 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIDesktopWidgetWatchdog.h
@@ -105,6 +105,11 @@ public:
bool isFakeScreenDetected() const;
#endif
+ /** Returns device-pixel-ratio of the host-screen with @a iHostScreenIndex. */
+ double devicePixelRatio(int iHostScreenIndex = -1);
+ /** Returns device-pixel-ratio of the host-screen which contains @a pWidget. */
+ double devicePixelRatio(QWidget *pWidget);
+
private slots:
#if QT_VERSION == 0
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.cpp b/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.cpp
index cec73bc..17462d7 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIIconPool.cpp
@@ -46,7 +46,8 @@ QPixmap UIIconPool::pixmap(const QString &strName)
QIcon icon = iconSet(strName);
/* Return pixmap of first available size: */
- return icon.pixmap(icon.availableSizes().first());
+ const int iHint = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
+ return icon.pixmap(icon.availableSizes().value(0, QSize(iHint, iHint)));
}
/* static */
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/UIVersion.h b/src/VBox/Frontends/VirtualBox/src/globals/UIVersion.h
new file mode 100644
index 0000000..2f706f0
--- /dev/null
+++ b/src/VBox/Frontends/VirtualBox/src/globals/UIVersion.h
@@ -0,0 +1,128 @@
+/* $Id: UIVersion.h $ */
+/** @file
+ * VBox Qt GUI - UIVersion class declaration/implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2018 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 ___UIVersion_h___
+#define ___UIVersion_h___
+
+/** Represents VirtualBox version wrapper. */
+class UIVersion
+{
+public:
+
+ /** Constructs default object. */
+ UIVersion()
+ : m_x(-1), m_y(-1), m_z(-1)
+ {}
+
+ /** Constructs object based on parsed @a strVersion. */
+ UIVersion(const QString &strVersion)
+ : m_x(-1), m_y(-1), m_z(-1)
+ {
+ const QStringList versionStack = strVersion.split('.');
+ if (versionStack.size() > 0)
+ m_x = versionStack[0].toInt();
+ if (versionStack.size() > 1)
+ m_y = versionStack[1].toInt();
+ if (versionStack.size() > 2)
+ m_z = versionStack[2].toInt();
+ }
+
+ /** Assigns this object with value of @a another. */
+ UIVersion &operator=(const UIVersion &another)
+ {
+ m_x = another.x();
+ m_y = another.y();
+ m_z = another.z();
+ return *this;
+ }
+
+ /** Returns whether this object is valid. */
+ bool isValid() const { return (m_x != -1) && (m_y != -1) && (m_z != -1); }
+
+ /** Returns whether this object is equal to @a other. */
+ bool equal(const UIVersion &other) const { return (m_x == other.m_x) && (m_y == other.m_y) && (m_z == other.m_z); }
+ /** Checks whether this object is equal to @a other. */
+ bool operator==(const UIVersion &other) const { return equal(other); }
+ /** Checks whether this object is NOT equal to @a other. */
+ bool operator!=(const UIVersion &other) const { return !equal(other); }
+
+ /** Checks whether this object is lass than @a other. */
+ bool operator<(const UIVersion &other) const
+ {
+ return (m_x < other.m_x)
+ || (m_x == other.m_x && m_y < other.m_y)
+ || (m_x == other.m_x && m_y == other.m_y && m_z < other.m_z);
+ }
+ /** Checks whether this object is more than @a other. */
+ bool operator>(const UIVersion &other) const
+ {
+ return (m_x > other.m_x)
+ || (m_x == other.m_x && m_y > other.m_y)
+ || (m_x == other.m_x && m_y == other.m_y && m_z > other.m_z);
+ }
+
+ /** Returns object string representation. */
+ QString toString() const { return QString("%1.%2.%3").arg(m_x).arg(m_y).arg(m_z); }
+
+ /** Returns the object X value. */
+ int x() const { return m_x; }
+ /** Returns the object Y value. */
+ int y() const { return m_y; }
+ /** Returns the object Z value. */
+ int z() const { return m_z; }
+
+ /** Defines the object X value. */
+ void setX(int x) { m_x = x; }
+ /** Defines the object Y value. */
+ void setY(int y) { m_y = y; }
+ /** Defines the object Z value. */
+ void setZ(int z) { m_z = z; }
+
+ /** Returns effective released version guessed or hardcoded for this one version.
+ * This can be even the version itself. */
+ UIVersion effectiveRelasedVersion() const
+ {
+ /* First, we just copy the current one: */
+ UIVersion version = *this;
+
+ /* If this version being developed: */
+ if (version.z() % 2 == 1)
+ {
+ /* If this version being developed on release branch (we guess the right one): */
+ if (version.z() < 97)
+ version.setZ(version.z() - 1);
+ /* If this version being developed on trunk (we use hardcoded one for now): */
+ else
+ version.setZ(6); /* Current .z for 5.2.z */
+ }
+
+ /* Finally, we just return that we have: */
+ return version;
+ }
+
+private:
+
+ /** Holds the object X value. */
+ int m_x;
+ /** Holds the object Y value. */
+ int m_y;
+ /** Holds the object Z value. */
+ int m_z;
+};
+
+#endif /* !___UIVersion_h___ */
+
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
index 108960e..e9dc003 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
@@ -3273,27 +3273,29 @@ void VBoxGlobal::setTopLevelGeometry(QWidget *pWidget, int x, int y, int w, int
* unconditionally. By calling ConfigureWindow directly, Qt will see
* our change request as an externally triggered one on success and not
* at all if it is rejected. */
+ const double dDPR = gpDesktop->devicePixelRatio(pWidget);
uint16_t fMask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
- uint32_t values[] = { (uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h };
+ uint32_t values[] = { (uint32_t)(x * dDPR), (uint32_t)(y * dDPR),
+ (uint32_t)(w * dDPR), (uint32_t)(h * dDPR) };
xcb_configure_window(QX11Info::connection(), (xcb_window_t)pWidget->winId(),
fMask, values);
xcb_size_hints_t hints;
hints.flags = 1 /* XCB_ICCCM_SIZE_HINT_US_POSITION */
| 2 /* XCB_ICCCM_SIZE_HINT_US_SIZE */
| 512 /* XCB_ICCCM_SIZE_P_WIN_GRAVITY */;
- hints.x = x;
- hints.y = y;
- hints.width = w;
- hints.height = h;
- hints.min_width = pWidget->minimumSize().width();
- hints.min_height = pWidget->minimumSize().height();
- hints.max_width = pWidget->maximumSize().width();
- hints.max_height = pWidget->maximumSize().height();
- hints.width_inc = pWidget->sizeIncrement().width();
- hints.height_inc = pWidget->sizeIncrement().height();
- hints.base_width = pWidget->baseSize().width();
- hints.base_height = pWidget->baseSize().height();
+ hints.x = x * dDPR;
+ hints.y = y * dDPR;
+ hints.width = w * dDPR;
+ hints.height = h * dDPR;
+ hints.min_width = pWidget->minimumSize().width() * dDPR;
+ hints.min_height = pWidget->minimumSize().height() * dDPR;
+ hints.max_width = pWidget->maximumSize().width() * dDPR;
+ hints.max_height = pWidget->maximumSize().height() * dDPR;
+ hints.width_inc = pWidget->sizeIncrement().width() * dDPR;
+ hints.height_inc = pWidget->sizeIncrement().height() * dDPR;
+ hints.base_width = pWidget->baseSize().width() * dDPR;
+ hints.base_height = pWidget->baseSize().height() * dDPR;
hints.win_gravity = XCB_GRAVITY_STATIC;
if (hints.min_width > 0 || hints.min_height > 0)
hints.flags |= 16 /* XCB_ICCCM_SIZE_HINT_P_MIN_SIZE */;
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxVersion.h b/src/VBox/Frontends/VirtualBox/src/globals/VBoxVersion.h
deleted file mode 100644
index 6bdd21e..0000000
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxVersion.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* $Id: VBoxVersion.h $ */
-/** @file
- * VBox Qt GUI - VBoxVersion class declaration.
- */
-
-/*
- * Copyright (C) 2006-2017 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef ___VBoxVersion_h___
-#define ___VBoxVersion_h___
-
-/**
- * Represents VirtualBox version wrapper
- */
-class VBoxVersion
-{
-public:
-
- VBoxVersion() : m_x(-1), m_y(-1), m_z(-1) {}
-
- VBoxVersion(const QString &strVersion)
- : m_x(-1), m_y(-1), m_z(-1)
- {
- QStringList versionStack = strVersion.split('.');
- if (versionStack.size() > 0)
- m_x = versionStack[0].toInt();
- if (versionStack.size() > 1)
- m_y = versionStack[1].toInt();
- if (versionStack.size() > 2)
- m_z = versionStack[2].toInt();
- }
-
- VBoxVersion& operator=(const VBoxVersion &other) { m_x = other.x(); m_y = other.y(); m_z = other.z(); return *this; }
-
- bool isValid() const { return m_x != -1 && m_y != -1 && m_z != -1; }
-
- bool equal(const VBoxVersion &other) const { return (m_x == other.m_x) && (m_y == other.m_y) && (m_z == other.m_z); }
- bool operator==(const VBoxVersion &other) const { return equal(other); }
- bool operator!=(const VBoxVersion &other) const { return !equal(other); }
-
- bool operator<(const VBoxVersion &other) const
- {
- return (m_x < other.m_x) ||
- (m_x == other.m_x && m_y < other.m_y) ||
- (m_x == other.m_x && m_y == other.m_y && m_z < other.m_z);
- }
- bool operator>(const VBoxVersion &other) const
- {
- return (m_x > other.m_x) ||
- (m_x == other.m_x && m_y > other.m_y) ||
- (m_x == other.m_x && m_y == other.m_y && m_z > other.m_z);
- }
-
- QString toString() const
- {
- return QString("%1.%2.%3").arg(m_x).arg(m_y).arg(m_z);
- }
-
- int x() const { return m_x; }
- int y() const { return m_y; }
- int z() const { return m_z; }
-
-private:
-
- int m_x;
- int m_y;
- int m_z;
-};
-
-#endif // !___VBoxVersion_h___
-
diff --git a/src/VBox/Frontends/VirtualBox/src/medium/UIMedium.cpp b/src/VBox/Frontends/VirtualBox/src/medium/UIMedium.cpp
index 6453584..c0fe991 100644
--- a/src/VBox/Frontends/VirtualBox/src/medium/UIMedium.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/medium/UIMedium.cpp
@@ -472,7 +472,7 @@ QPixmap UIMedium::icon(bool fNoDiffs /* = false */, bool fCheckRO /* = false */)
if (fCheckRO && m_fReadOnly)
{
QIcon icon = UIIconPool::iconSet(":/hd_new_16px.png");
- pixmap = VBoxGlobal::joinPixmaps(pixmap, icon.pixmap(icon.availableSizes().first()));
+ pixmap = VBoxGlobal::joinPixmaps(pixmap, icon.pixmap(icon.availableSizes().value(0, QSize(16, 16))));
}
return pixmap;
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderAdditions.cpp b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderAdditions.cpp
index adc4888..01726e9 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderAdditions.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderAdditions.cpp
@@ -30,6 +30,7 @@
# include "VBoxGlobal.h"
# include "UIMessageCenter.h"
# include "UIModalWindowManager.h"
+# include "UIVersion.h"
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
@@ -60,32 +61,13 @@ UIDownloaderAdditions::UIDownloaderAdditions()
if (!m_spInstance)
m_spInstance = this;
- /* Get version number and adjust it for test and trunk builds, both have
- odd build numbers. The server only has official releases. */
- QString strVersion = vboxGlobal().vboxVersionStringNormalized();
- QChar qchLastDigit = strVersion[strVersion.length() - 1];
- if ( qchLastDigit == '1'
- || qchLastDigit == '3'
- || qchLastDigit == '5'
- || qchLastDigit == '7'
- || qchLastDigit == '9')
- {
- if ( !strVersion.endsWith(".51")
- && !strVersion.endsWith(".53")
- && !strVersion.endsWith(".97")
- && !strVersion.endsWith(".99"))
- strVersion[strVersion.length() - 1] = qchLastDigit.toLatin1() - 1;
- else
- {
- strVersion.chop(2);
- strVersion += "10"; /* Current for 5.0.x */
- }
- }
+ /* Get version number and adjust it for test and trunk builds. The server only has official releases. */
+ const QString strVersion = UIVersion(vboxGlobal().vboxVersionStringNormalized()).effectiveRelasedVersion().toString();
/* Prepare source/target: */
- const QString strSourceName = QString("VBoxGuestAdditions_%1.iso").arg(strVersion);
- const QString strSourceFolder = QString("http://download.virtualbox.org/virtualbox/%1/").arg(strVersion);
- const QString strSource = strSourceFolder + strSourceName;
+ const QString strSourceName = QString("%1_%2.iso").arg(GUI_GuestAdditionsName, strVersion);
+ const QString strSourcePath = QString("https://download.virtualbox.org/virtualbox/%1/").arg(strVersion);
+ const QString strSource = strSourcePath + strSourceName;
const QString strPathSHA256SumsFile = QString("https://www.virtualbox.org/download/hashes/%1/SHA256SUMS").arg(strVersion);
const QString strTarget = QDir(vboxGlobal().homeFolder()).absoluteFilePath(strSourceName);
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderExtensionPack.cpp b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderExtensionPack.cpp
index 188083b..2c70bf3 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderExtensionPack.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderExtensionPack.cpp
@@ -30,6 +30,7 @@
# include "VBoxGlobal.h"
# include "UIMessageCenter.h"
# include "UIModalWindowManager.h"
+# include "UIVersion.h"
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
@@ -60,18 +61,16 @@ UIDownloaderExtensionPack::UIDownloaderExtensionPack()
if (!m_spInstance)
m_spInstance = this;
+ /* Get version number and adjust it for test and trunk builds. The server only has official releases. */
+ const QString strVersion = UIVersion(vboxGlobal().vboxVersionStringNormalized()).effectiveRelasedVersion().toString();
+
/* Prepare source/target: */
- QString strVersion = vboxGlobal().vboxVersionStringNormalized();
- QString strExtPackUnderscoredName(QString(GUI_ExtPackName).replace(' ', '_'));
- QString strTemplateSourcePath("http://download.virtualbox.org/virtualbox/%1/");
- QString strTemplateSourceName(QString("%1-%2.vbox-extpack").arg(strExtPackUnderscoredName));
- QString strSourcePath(strTemplateSourcePath.arg(strVersion));
- QString strSourceName(strTemplateSourceName.arg(strVersion));
- QString strSource(strSourcePath + strSourceName);
- QString strPathSHA256SumsFile = QString("https://www.virtualbox.org/download/hashes/%1/SHA256SUMS").arg(strVersion);
- QString strTargetPath(vboxGlobal().homeFolder());
- QString strTargetName(strSourceName);
- QString strTarget(QDir(strTargetPath).absoluteFilePath(strTargetName));
+ const QString strUnderscoredName = QString(GUI_ExtPackName).replace(' ', '_');
+ const QString strSourceName = QString("%1-%2.vbox-extpack").arg(strUnderscoredName, strVersion);
+ const QString strSourcePath = QString("https://download.virtualbox.org/virtualbox/%1/").arg(strVersion);
+ const QString strSource = strSourcePath + strSourceName;
+ const QString strPathSHA256SumsFile = QString("https://www.virtualbox.org/download/hashes/%1/SHA256SUMS").arg(strVersion);
+ const QString strTarget = QDir(vboxGlobal().homeFolder()).absoluteFilePath(strSourceName);
/* Set source/target: */
setSource(strSource);
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderUserManual.cpp b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderUserManual.cpp
index f328030..8260220 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderUserManual.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIDownloaderUserManual.cpp
@@ -30,6 +30,7 @@
# include "VBoxGlobal.h"
# include "UIMessageCenter.h"
# include "UIModalWindowManager.h"
+# include "UIVersion.h"
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
@@ -57,13 +58,18 @@ UIDownloaderUserManual::UIDownloaderUserManual()
if (!m_spInstance)
m_spInstance = this;
+ /* Get version number and adjust it for test and trunk builds. The server only has official releases. */
+ const QString strVersion = UIVersion(vboxGlobal().vboxVersionStringNormalized()).effectiveRelasedVersion().toString();
+
/* Compose User Manual filename: */
QString strUserManualFullFileName = vboxGlobal().helpFile();
QString strUserManualShortFileName = QFileInfo(strUserManualFullFileName).fileName();
/* Add sources: */
- addSource(QString("http://download.virtualbox.org/virtualbox/%1/").arg(vboxGlobal().vboxVersionStringNormalized()) + strUserManualShortFileName);
- addSource(QString("http://download.virtualbox.org/virtualbox/") + strUserManualShortFileName);
+ QString strSource1 = QString("https://download.virtualbox.org/virtualbox/%1/").arg(strVersion) + strUserManualShortFileName;
+ QString strSource2 = QString("https://download.virtualbox.org/virtualbox/") + strUserManualShortFileName;
+ addSource(strSource1);
+ addSource(strSource2);
/* Set target: */
QString strUserManualDestination = QDir(vboxGlobal().homeFolder()).absoluteFilePath(strUserManualShortFileName);
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
index 230f894..61822d9 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
@@ -89,8 +89,6 @@ public:
const QByteArray& readAll() const { return m_reply; }
/** Returns value for the cached reply header of the passed @a type. */
QString header(UINetworkReply::KnownHeader type) const;
- /** Returns value for the cached reply attribute of the passed @a code. */
- QVariant attribute(UINetworkReply::KnownAttribute code) const { /** @todo r=dsen: Fix that. */ Q_UNUSED(code); return QVariant(); }
/** Returns short descriptive context of thread's current operation. */
const QString context() const { return m_strContext; }
@@ -264,8 +262,6 @@ public:
QByteArray readAll() const { return m_pThread->readAll(); }
/** Returns value for the cached reply header of the passed @a type. */
QString header(UINetworkReply::KnownHeader type) const { return m_pThread->header(type); }
- /** Returns value for the cached reply attribute of the passed @a code. */
- QVariant attribute(UINetworkReply::KnownAttribute code) const { return m_pThread->attribute(code); }
private slots:
@@ -368,6 +364,7 @@ QString UINetworkReplyPrivateThread::header(UINetworkReply::KnownHeader type) co
case UINetworkReply::ContentTypeHeader: return m_headers.value("Content-Type");
case UINetworkReply::ContentLengthHeader: return m_headers.value("Content-Length");
case UINetworkReply::LastModifiedHeader: return m_headers.value("Last-Modified");
+ case UINetworkReply::LocationHeader: return m_headers.value("Location");
default: break;
}
/* Return null-string by default: */
@@ -550,6 +547,17 @@ int UINetworkReplyPrivateThread::performMainRequest()
m_headers[values.at(0)] = values.at(1);
}
+ /* Special handling of redirection header: */
+ if (rc == VERR_HTTP_REDIRECTED)
+ {
+ char *pszBuf = 0;
+ const int rrc = RTHttpGetRedirLocation(m_hHttp, &pszBuf);
+ if (RT_SUCCESS(rrc))
+ m_headers["Location"] = QString(pszBuf);
+ if (pszBuf)
+ RTMemFree(pszBuf);
+ }
+
break;
}
case UINetworkRequestType_GET:
@@ -1045,11 +1053,6 @@ QVariant UINetworkReply::header(UINetworkReply::KnownHeader header) const
return m_pReply->header(header);
}
-QVariant UINetworkReply::attribute(UINetworkReply::KnownAttribute code) const
-{
- return m_pReply->attribute(code);
-}
-
#include "UINetworkReply.moc"
#endif /* !VBOX_GUI_IN_TST_SSL_CERT_DOWNLOADS */
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.h b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.h
index 31fc100..5aa7d54 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.h
+++ b/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.h
@@ -74,14 +74,7 @@ public:
ContentTypeHeader,
ContentLengthHeader,
LastModifiedHeader,
- };
-
- /** Known attribute types.
- * Came from QtNetwork module.
- * More to go on demand when necessary. */
- enum KnownAttribute
- {
- RedirectionTargetAttribute,
+ LocationHeader,
};
/** Constructs network-reply of the passed @a type for the passed @a url and @a requestHeaders. */
@@ -104,8 +97,6 @@ public:
QByteArray readAll() const;
/** Returns value for the cached reply header of the passed @a type. */
QVariant header(UINetworkReply::KnownHeader header) const;
- /** Returns value for the cached reply attribute of the passed @a code. */
- QVariant attribute(UINetworkReply::KnownAttribute code) const;
private:
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequest.cpp b/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequest.cpp
index 553d36e..fdb587a 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequest.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UINetworkRequest.cpp
@@ -77,58 +77,76 @@ void UINetworkRequest::sltHandleNetworkReplyFinish()
if (!m_pReply)
return;
+ /* If network-reply has no errors: */
+ if (m_pReply->error() == UINetworkReply::NoError)
+ {
+ /* Notify own network-request listeners: */
+ emit sigFinished();
+ /* Notify common network-request listeners: */
+ emit sigFinished(m_uuid);
+ }
/* If network-request was canceled: */
- if (m_pReply->error() == UINetworkReply::OperationCanceledError)
+ else if (m_pReply->error() == UINetworkReply::OperationCanceledError)
{
/* Notify network-manager: */
emit sigCanceled(m_uuid);
}
- /* If network-reply has no errors: */
- else if (m_pReply->error() == UINetworkReply::NoError)
+ /* If some other error occured: */
+ else
{
- /* Check if redirection required: */
- QUrl redirect = m_pReply->attribute(UINetworkReply::RedirectionTargetAttribute).toUrl();
- if (redirect.isValid())
- {
- /* Cleanup current network-reply first: */
- cleanupNetworkReply();
-
- /* Choose redirect-source as current url: */
- m_url = redirect;
+ /* Check if we are able to handle error: */
+ bool fErrorHandled = false;
- /* Create new network-reply finally: */
- prepareNetworkReply();
- }
- else
+ /* Handle redirection: */
+ switch (m_pReply->error())
{
- /* Notify own network-request listeners: */
- emit sigFinished();
- /* Notify common network-request listeners: */
- emit sigFinished(m_uuid);
+ case UINetworkReply::ContentReSendError:
+ {
+ /* Check whether redirection link was acquired: */
+ const QString strRedirect = m_pReply->header(UINetworkReply::LocationHeader).toString();
+ if (!strRedirect.isEmpty())
+ {
+ /* Cleanup current network-reply first: */
+ cleanupNetworkReply();
+
+ /* Choose redirect-source as current url: */
+ m_url = strRedirect;
+
+ /* Create new network-reply finally: */
+ prepareNetworkReply();
+
+ /* Mark this error handled: */
+ fErrorHandled = true;
+ }
+ break;
+ }
+ default:
+ break;
}
- }
- /* If some error occured: */
- else
- {
- /* Check if we have other urls in queue: */
- if (m_iUrlIndex < m_urls.size() - 1)
- {
- /* Cleanup current network-reply first: */
- cleanupNetworkReply();
-
- /* Choose next url as current: */
- ++m_iUrlIndex;
- m_url = m_urls.at(m_iUrlIndex);
- /* Create new network-reply finally: */
- prepareNetworkReply();
- }
- else
+ /* If error still unhandled: */
+ if (!fErrorHandled)
{
- /* Notify own network-request listeners: */
- emit sigFailed(m_pReply->errorString());
- /* Notify common network-request listeners: */
- emit sigFailed(m_uuid, m_pReply->errorString());
+ /* Check if we have other urls in queue: */
+ if (m_iUrlIndex < m_urls.size() - 1)
+ {
+ /* Cleanup current network-reply first: */
+ cleanupNetworkReply();
+
+ /* Choose next url as current: */
+ ++m_iUrlIndex;
+ m_url = m_urls.at(m_iUrlIndex);
+
+ /* Create new network-reply finally: */
+ prepareNetworkReply();
+ }
+ else
+ {
+ /* Notify own network-request listeners: */
+ emit sigFailed(m_pReply->errorString());
+ /* Notify common network-request listeners: */
+ emit sigFailed(m_uuid, m_pReply->errorString());
+ }
}
}
}
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.cpp b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.cpp
index 40d83c0..c530892 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.cpp
@@ -101,7 +101,7 @@ bool VBoxUpdateData::isNeedToCheck() const
return true;
/* Return 'true' if saved version value is NOT valid or NOT equal to current: */
- if (!version().isValid() || version() != VBoxVersion(vboxGlobal().vboxVersionStringNormalized()))
+ if (!version().isValid() || version() != UIVersion(vboxGlobal().vboxVersionStringNormalized()))
return true;
/* Return 'false' in all other cases: */
@@ -142,7 +142,7 @@ QString VBoxUpdateData::branchName() const
return QString();
}
-VBoxVersion VBoxUpdateData::version() const
+UIVersion VBoxUpdateData::version() const
{
return m_version;
}
@@ -184,7 +184,7 @@ void VBoxUpdateData::decode()
/* Parse 'version' value: */
if (parser.size() > 3)
{
- m_version = VBoxVersion(parser[3]);
+ m_version = UIVersion(parser[3]);
}
}
}
@@ -218,7 +218,7 @@ void VBoxUpdateData::encode()
m_branchIndex == BranchAllRelease ? "allrelease" : "stable";
/* Encode 'version' value: */
- QString versionValue = VBoxVersion(vboxGlobal().vboxVersionStringNormalized()).toString();
+ QString versionValue = UIVersion(vboxGlobal().vboxVersionStringNormalized()).toString();
/* Composite m_strData: */
m_strData = QString("%1, %2, %3, %4").arg(remindPeriod, remindDate, branchValue, versionValue);
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.h b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.h
index 092d2c0..6f94800 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.h
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateDefs.h
@@ -18,11 +18,12 @@
#ifndef ___UIUpdateDefs_h___
#define ___UIUpdateDefs_h___
-/* Global includes: */
+/* Qt includes: */
#include <QDate>
-/* Local includes: */
-#include "VBoxVersion.h"
+/* GUI includes: */
+#include "UIVersion.h"
+
/* This structure is used to store retranslated reminder values. */
struct VBoxUpdateDay
@@ -37,6 +38,7 @@ struct VBoxUpdateDay
};
typedef QList<VBoxUpdateDay> VBoxUpdateDayList;
+
/* This class is used to encode/decode update data. */
class VBoxUpdateData
{
@@ -83,7 +85,7 @@ public:
QString date() const;
BranchType branchIndex() const;
QString branchName() const;
- VBoxVersion version() const;
+ UIVersion version() const;
private:
@@ -97,8 +99,8 @@ private:
PeriodType m_periodIndex;
QDate m_date;
BranchType m_branchIndex;
- VBoxVersion m_version;
+ UIVersion m_version;
};
-#endif // !___UIUpdateDefs_h___
+#endif /* !___UIUpdateDefs_h___ */
diff --git a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateManager.cpp b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateManager.cpp
index 93f1c89..da0adba 100644
--- a/src/VBox/Frontends/VirtualBox/src/net/UIUpdateManager.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/net/UIUpdateManager.cpp
@@ -365,22 +365,32 @@ private slots:
}
/* Get VirtualBox version: */
- QString strVBoxVersion(vboxGlobal().vboxVersionStringNormalized());
- QByteArray abVBoxVersion = strVBoxVersion.toUtf8();
- VBoxVersion vboxVersion(strVBoxVersion);
-
+ UIVersion vboxVersion(vboxGlobal().vboxVersionStringNormalized());
/* Get extension pack version: */
QString strExtPackVersion(extPack.GetVersion());
QByteArray abExtPackVersion = strExtPackVersion.toUtf8();
- /* Skip the check in unstable VBox version and if the extension pack
- is equal to or newer than VBox.
+ /* If this version being developed: */
+ if (vboxVersion.z() % 2 == 1)
+ {
+ /* If this version being developed on release branch (we use released one): */
+ if (vboxVersion.z() < 97)
+ vboxVersion.setZ(vboxVersion.z() - 1);
+ /* If this version being developed on trunk (we skip check at all): */
+ else
+ {
+ emit sigStepComplete();
+ return;
+ }
+ }
+
+ /* Get updated VirtualBox version: */
+ const QString strVBoxVersion = vboxVersion.toString();
- Note! Use RTStrVersionCompare for the comparison here as it takes
- the beta/alpha/preview/whatever tags into consideration when
- comparing versions. */
- if ( vboxVersion.z() % 2 != 0
- || RTStrVersionCompare(abExtPackVersion.constData(), abVBoxVersion.constData()) >= 0)
+ /* Skip the check if the extension pack is equal to or newer than VBox.
+ * Note! Use RTStrVersionCompare for the comparison here as it takes the
+ * beta/alpha/preview/whatever tags into consideration when comparing versions. */
+ if (RTStrVersionCompare(abExtPackVersion.constData(), strVBoxVersion.toUtf8().constData()) >= 0)
{
emit sigStepComplete();
return;
diff --git a/src/VBox/Frontends/VirtualBox/src/platform/darwin/UICocoaSpecialControls.mm b/src/VBox/Frontends/VirtualBox/src/platform/darwin/UICocoaSpecialControls.mm
index 67d9211..0b16551 100644
--- a/src/VBox/Frontends/VirtualBox/src/platform/darwin/UICocoaSpecialControls.mm
+++ b/src/VBox/Frontends/VirtualBox/src/platform/darwin/UICocoaSpecialControls.mm
@@ -597,7 +597,7 @@ void UICocoaSegmentedButton::setToolTip(int iSegment, const QString &strTip)
void UICocoaSegmentedButton::setIcon(int iSegment, const QIcon& icon)
{
- QImage image = toGray(icon.pixmap(icon.availableSizes().first()).toImage());
+ QImage image = toGray(icon.pixmap(icon.availableSizes().value(0, QSize(16, 16))).toImage());
NSImage *pNSimage = [::darwinToNSImageRef(&image) autorelease];
[nativeRef() setImage: pNSimage forSegment: iSegment];
diff --git a/src/VBox/Frontends/VirtualBox/src/precomp.h b/src/VBox/Frontends/VirtualBox/src/precomp.h
index 2728635..1d4788b 100644
--- a/src/VBox/Frontends/VirtualBox/src/precomp.h
+++ b/src/VBox/Frontends/VirtualBox/src/precomp.h
@@ -656,7 +656,7 @@
are used as enum constants in VBoxUtils.h. Don't bother undefining
the redefinitions, just prevent the inclusion of the header! */
#include "VBoxUtils.h"
-#include "VBoxVersion.h"
+#include "UIVersion.h"
#ifdef VBOX_WS_X11
# include "VBoxX11Helper.h"
#endif
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
index f1c79f7..5ace407 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
@@ -2192,7 +2192,7 @@ void UIMachineLogic::sltInstallGuestAdditions()
/* Check for the already registered image */
CVirtualBox vbox = vboxGlobal().virtualBox();
- const QString &name = QString("VBoxGuestAdditions_%1.iso").arg(vboxGlobal().vboxVersionStringNormalized());
+ const QString &strName = QString("%1_%2.iso").arg(GUI_GuestAdditionsName, vboxGlobal().vboxVersionStringNormalized());
CMediumVector vec = vbox.GetDVDImages();
for (CMediumVector::ConstIterator it = vec.begin(); it != vec.end(); ++ it)
@@ -2200,7 +2200,7 @@ void UIMachineLogic::sltInstallGuestAdditions()
QString path = it->GetLocation();
/* Compare the name part ignoring the file case */
QString fn = QFileInfo(path).fileName();
- if (RTPathCompare(name.toUtf8().constData(), fn.toUtf8().constData()) == 0)
+ if (RTPathCompare(strName.toUtf8().constData(), fn.toUtf8().constData()) == 0)
return uisession()->sltInstallGuestAdditionsFrom(path);
}
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
index 03b9adb..204cdb4 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp
@@ -95,17 +95,6 @@ void UIMachineWindow::destroy(UIMachineWindow *pWhichWindow)
void UIMachineWindow::prepare()
{
-#ifdef VBOX_WS_X11
- /* Prepare default class/name values: */
- const QString strWindowClass = QString("VirtualBox Machine");
- QString strWindowName = strWindowClass;
- /* Check if we want Window Manager to distinguish Virtual Machine windows: */
- if (gEDataManager->distinguishMachineWindowGroups(vboxGlobal().managedVMUuid()))
- strWindowName = QString("VirtualBox Machine UUID: %1").arg(vboxGlobal().managedVMUuid());
- /* Assign WM_CLASS property: */
- vboxGlobal().setWMClass(this, strWindowName, strWindowClass);
-#endif
-
/* Prepare session-connections: */
prepareSessionConnections();
@@ -138,6 +127,17 @@ void UIMachineWindow::prepare()
/* Update all the elements: */
updateAppearanceOf(UIVisualElement_AllStuff);
+
+#ifdef VBOX_WS_X11
+ /* Prepare default class/name values: */
+ const QString strWindowClass = QString("VirtualBox Machine");
+ QString strWindowName = strWindowClass;
+ /* Check if we want Window Manager to distinguish Virtual Machine windows: */
+ if (gEDataManager->distinguishMachineWindowGroups(vboxGlobal().managedVMUuid()))
+ strWindowName = QString("VirtualBox Machine UUID: %1").arg(vboxGlobal().managedVMUuid());
+ /* Assign WM_CLASS property: */
+ VBoxGlobal::setWMClass(this, strWindowName, strWindowClass);
+#endif
}
void UIMachineWindow::cleanup()
@@ -630,4 +630,3 @@ void UIMachineWindow::handleStandardWindowButtonCallback(StandardWindowButtonTyp
}
}
#endif /* VBOX_WS_MAC */
-
diff --git a/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp b/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp
index 2ab4885..21e8779 100644
--- a/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp
@@ -1316,7 +1316,7 @@ void UISelectorWindow::prepare()
{
#ifdef VBOX_WS_X11
/* Assign same name to both WM_CLASS name & class for now: */
- vboxGlobal().setWMClass(this, "VirtualBox Manager", "VirtualBox Manager");
+ VBoxGlobal::setWMClass(this, "VirtualBox Manager", "VirtualBox Manager");
#endif
#ifdef VBOX_WS_MAC
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
index e2abd3b..c4bb483 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
@@ -265,7 +265,7 @@ void UISettingsSerializerProgress::prepare()
{
/* Configure label: */
const QIcon icon = UIIconPool::iconSet(":/progress_settings_90px.png");
- pLabelPixmap->setPixmap(icon.pixmap(icon.availableSizes().first()));
+ pLabelPixmap->setPixmap(icon.pixmap(icon.availableSizes().value(0, QSize(90, 90))));
/* Add label into layout: */
pLayoutPixmap->addWidget(pLabelPixmap);
}
diff --git a/src/VBox/Frontends/VirtualBox/src/wizards/UIWizard.cpp b/src/VBox/Frontends/VirtualBox/src/wizards/UIWizard.cpp
index e25779e..7cad722 100644
--- a/src/VBox/Frontends/VirtualBox/src/wizards/UIWizard.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/wizards/UIWizard.cpp
@@ -253,7 +253,7 @@ void UIWizard::resizeToGoldenRatio()
const double dRatio = (double)iIconMetric / 32;
/* Load pixmap to icon first: */
QIcon icon = UIIconPool::iconSet(m_strWatermarkName);
- QSize size = icon.availableSizes().first();
+ QSize size = icon.availableSizes().value(0, QSize(145, 290));
size *= dRatio;
/* We should take into account watermark like its assigned already: */
QPixmap watermarkPixmap(icon.pixmap(size));
@@ -490,7 +490,7 @@ void UIWizard::assignWatermarkHelper()
const double dRatio = (double)iIconMetric / 32;
/* Load pixmap to icon first: */
QIcon icon = UIIconPool::iconSet(m_strWatermarkName);
- QSize size = icon.availableSizes().first();
+ QSize size = icon.availableSizes().value(0, QSize(145, 290));
size *= dRatio;
/* Create initial watermark: */
QPixmap pixWaterMark(icon.pixmap(size));
diff --git a/src/VBox/GuestHost/OpenGL/Makefile.kmk b/src/VBox/GuestHost/OpenGL/Makefile.kmk
index 71024f2..3216b2a 100644
--- a/src/VBox/GuestHost/OpenGL/Makefile.kmk
+++ b/src/VBox/GuestHost/OpenGL/Makefile.kmk
@@ -515,10 +515,8 @@ VBoxOGLcrstate_CLEAN += $(VBOX_PATH_CROGL_GENFILES)/dump_gen.cpp
endif
ifneq ($(KBUILD_TARGET),win)
- ifeq ($(VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE),)
state_tracker/state_lists.c_CFLAGS += $(VBOX_GCC_Wno-pointer-sign)
VBoxOGLcrstate_CFLAGS +=
- endif
endif
ifdef VBOX_WITH_CRHGSMI
VBoxOGLcrstate_DEFS.win += VBOX_WITH_CRHGSMI
diff --git a/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.pyc b/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.pyc
index 63ca64f..ab613db 100644
Binary files a/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.pyc and b/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.pyc differ
diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_currenttypes.pyc b/src/VBox/GuestHost/OpenGL/packer/pack_currenttypes.pyc
index 72d6139..9725233 100644
Binary files a/src/VBox/GuestHost/OpenGL/packer/pack_currenttypes.pyc and b/src/VBox/GuestHost/OpenGL/packer/pack_currenttypes.pyc differ
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/convert.pyc b/src/VBox/GuestHost/OpenGL/state_tracker/convert.pyc
index 6677e09..968c903 100644
Binary files a/src/VBox/GuestHost/OpenGL/state_tracker/convert.pyc and b/src/VBox/GuestHost/OpenGL/state_tracker/convert.pyc differ
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/get_components.pyc b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.pyc
index 2053df4..f4196af 100644
Binary files a/src/VBox/GuestHost/OpenGL/state_tracker/get_components.pyc and b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.pyc differ
diff --git a/src/VBox/HostDrivers/Support/SUPDrv.cpp b/src/VBox/HostDrivers/Support/SUPDrv.cpp
index 036998c..38a1846 100644
--- a/src/VBox/HostDrivers/Support/SUPDrv.cpp
+++ b/src/VBox/HostDrivers/Support/SUPDrv.cpp
@@ -203,6 +203,7 @@ static SUPFUNC g_aFunctions[] =
{ "SUPR0GetPagingMode", (void *)(uintptr_t)SUPR0GetPagingMode },
{ "SUPR0GetSvmUsability", (void *)(uintptr_t)SUPR0GetSvmUsability },
{ "SUPR0GetVmxUsability", (void *)(uintptr_t)SUPR0GetVmxUsability },
+ { "SUPR0GetRawModeUsability", (void *)(uintptr_t)SUPR0GetRawModeUsability },
{ "SUPR0LockMem", (void *)(uintptr_t)SUPR0LockMem },
{ "SUPR0LowAlloc", (void *)(uintptr_t)SUPR0LowAlloc },
{ "SUPR0LowFree", (void *)(uintptr_t)SUPR0LowFree },
@@ -2257,7 +2258,7 @@ static int supdrvIOCtlInnerUnrestricted(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt,
REQ_CHECK_SIZES(SUP_IOCTL_VT_CAPS);
/* execute */
- pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.Caps);
+ pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.fCaps);
if (RT_FAILURE(pReq->Hdr.rc))
pReq->Hdr.cbOut = sizeof(pReq->Hdr);
return 0;
@@ -2476,7 +2477,7 @@ static int supdrvIOCtlInnerRestricted(uintptr_t uIOCtl, PSUPDRVDEVEXT pDevExt, P
REQ_CHECK_SIZES(SUP_IOCTL_VT_CAPS);
/* execute */
- pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.Caps);
+ pReq->Hdr.rc = SUPR0QueryVTCaps(pSession, &pReq->u.Out.fCaps);
if (RT_FAILURE(pReq->Hdr.rc))
pReq->Hdr.cbOut = sizeof(pReq->Hdr);
return 0;
@@ -4061,6 +4062,26 @@ SUPR0DECL(int) SUPR0GetCurrentGdtRw(RTHCUINTPTR *pGdtRw)
/**
+ * Checks if raw-mode is usable on this system.
+ *
+ * The reasons why raw-mode isn't safe to use are host specific. For example on
+ * Windows the Hyper-V root partition may perhapse not allow important bits in
+ * CR4 to be changed, which would make it impossible to do a world switch.
+ *
+ * @returns VBox status code.
+ */
+SUPR0DECL(int) SUPR0GetRawModeUsability(void)
+{
+#ifdef RT_OS_WINDOWS
+ return supdrvOSGetRawModeUsability();
+#else
+ return VINF_SUCCESS;
+#endif
+}
+
+
+
+/**
* Checks if Intel VT-x feature is usable on this CPU.
*
* @returns VBox status code.
@@ -4076,7 +4097,7 @@ SUPR0DECL(int) SUPR0GetCurrentGdtRw(RTHCUINTPTR *pGdtRw)
*/
SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous)
{
- uint64_t u64FeatMsr;
+ uint64_t fFeatMsr;
bool fMaybeSmxMode;
bool fMsrLocked;
bool fSmxVmxAllowed;
@@ -4086,11 +4107,11 @@ SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous)
Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
- u64FeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
+ fFeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
fMaybeSmxMode = RT_BOOL(ASMGetCR4() & X86_CR4_SMXE);
- fMsrLocked = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK);
- fSmxVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON);
- fVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON);
+ fMsrLocked = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK);
+ fSmxVmxAllowed = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON);
+ fVmxAllowed = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON);
fIsSmxModeAmbiguous = false;
rc = VERR_INTERNAL_ERROR_5;
@@ -4148,31 +4169,29 @@ SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous)
&& (fFeaturesECX & X86_CPUID_FEATURE_ECX_SMX))
fSmxVmxHwSupport = true;
- u64FeatMsr |= MSR_IA32_FEATURE_CONTROL_LOCK
- | MSR_IA32_FEATURE_CONTROL_VMXON;
+ fFeatMsr |= MSR_IA32_FEATURE_CONTROL_LOCK
+ | MSR_IA32_FEATURE_CONTROL_VMXON;
if (fSmxVmxHwSupport)
- u64FeatMsr |= MSR_IA32_FEATURE_CONTROL_SMX_VMXON;
+ fFeatMsr |= MSR_IA32_FEATURE_CONTROL_SMX_VMXON;
/*
* Commit.
*/
- ASMWrMsr(MSR_IA32_FEATURE_CONTROL, u64FeatMsr);
+ ASMWrMsr(MSR_IA32_FEATURE_CONTROL, fFeatMsr);
/*
* Verify.
*/
- u64FeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
- fMsrLocked = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK);
+ fFeatMsr = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
+ fMsrLocked = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_LOCK);
if (fMsrLocked)
{
- fSmxVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON);
- fVmxAllowed = RT_BOOL(u64FeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON);
+ fSmxVmxAllowed = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_SMX_VMXON);
+ fVmxAllowed = RT_BOOL(fFeatMsr & MSR_IA32_FEATURE_CONTROL_VMXON);
if ( fVmxAllowed
&& ( !fSmxVmxHwSupport
|| fSmxVmxAllowed))
- {
rc = VINF_SUCCESS;
- }
else
rc = !fSmxVmxHwSupport ? VERR_VMX_MSR_VMX_ENABLE_FAILED : VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED;
}
diff --git a/src/VBox/HostDrivers/Support/SUPDrvIOC.h b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
index 07e73dc..2ce1948 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvIOC.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvIOC.h
@@ -213,7 +213,7 @@ typedef SUPREQHDR *PSUPREQHDR;
*
* @remarks 0x002a0000 is used by 5.1. The next version number must be 0x002b0000.
*/
-#define SUPDRV_IOC_VERSION 0x00290000
+#define SUPDRV_IOC_VERSION 0x00290001
/** SUP_IOCTL_COOKIE. */
typedef struct SUPCOOKIE
@@ -1208,7 +1208,7 @@ typedef struct SUPVTCAPS
struct
{
/** The VT capability dword. */
- uint32_t Caps;
+ uint32_t fCaps;
} Out;
} u;
} SUPVTCAPS, *PSUPVTCAPS;
diff --git a/src/VBox/HostDrivers/Support/SUPDrvInternal.h b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
index 7dc4b88..c56da99 100644
--- a/src/VBox/HostDrivers/Support/SUPDrvInternal.h
+++ b/src/VBox/HostDrivers/Support/SUPDrvInternal.h
@@ -849,6 +849,7 @@ RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask
bool VBOXCALL supdrvOSSuspendVTxOnCpu(void);
void VBOXCALL supdrvOSResumeVTxOnCpu(bool fSuspended);
int VBOXCALL supdrvOSGetCurrentGdtRw(RTHCUINTPTR *pGdtRw);
+int VBOXCALL supdrvOSGetRawModeUsability(void);
/**
* Try open the image using the native loader.
diff --git a/src/VBox/HostDrivers/Support/SUPLib.cpp b/src/VBox/HostDrivers/Support/SUPLib.cpp
index 1377122..af3184b 100644
--- a/src/VBox/HostDrivers/Support/SUPLib.cpp
+++ b/src/VBox/HostDrivers/Support/SUPLib.cpp
@@ -275,8 +275,8 @@ SUPR3DECL(int) SUPR3InitEx(bool fUnrestricted, PSUPDRVSESSION *ppSession)
CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
- const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00280000
- ? 0x00280002
+ const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00290000
+ ? 0x00290001
: SUPDRV_IOC_VERSION & 0xffff0000;
CookieReq.u.In.u32MinVersion = uMinVersion;
rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
@@ -1688,13 +1688,13 @@ SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
Req.Hdr.rc = VERR_INTERNAL_ERROR;
- Req.u.Out.Caps = 0;
+ Req.u.Out.fCaps = 0;
int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
if (RT_SUCCESS(rc))
{
rc = Req.Hdr.rc;
if (RT_SUCCESS(rc))
- *pfCaps = Req.u.Out.Caps;
+ *pfCaps = Req.u.Out.fCaps;
}
return rc;
}
diff --git a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
index 12cf7d0..339f1c5 100644
--- a/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
+++ b/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
@@ -45,6 +45,7 @@
#include <iprt/semaphore.h>
#include <iprt/spinlock.h>
#include <iprt/string.h>
+#include <iprt/x86.h>
#include <VBox/log.h>
#include <VBox/err.h>
@@ -1872,6 +1873,71 @@ bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
}
+/**
+ * Checks whether we're allowed by Hyper-V to modify CR4.
+ */
+int VBOXCALL supdrvOSGetRawModeUsability(void)
+{
+ int rc = VINF_SUCCESS;
+
+#ifdef RT_ARCH_AMD64
+ /*
+ * Broadwell running W10 17083.100:
+ * CR4: 0x170678
+ * Evil mask: 0x170638
+ * X86_CR4_SMEP - evil
+ * X86_CR4_FSGSBASE - evil
+ * X86_CR4_PCIDE - evil
+ * X86_CR4_OSXSAVE - evil
+ * X86_CR4_OSFXSR - evil
+ * X86_CR4_OSXMMEEXCPT - evil
+ * X86_CR4_PSE - evil
+ * X86_CR4_PAE - evil
+ * X86_CR4_MCE - okay
+ * X86_CR4_DE - evil
+ */
+ if (ASMHasCpuId())
+ {
+ uint32_t cStd = ASMCpuId_EAX(0);
+ if (ASMIsValidStdRange(cStd))
+ {
+ uint32_t uIgn = 0;
+ uint32_t fEdxFeatures = 0;
+ uint32_t fEcxFeatures = 0;
+ ASMCpuIdExSlow(1, 0, 0, 0, &uIgn, &uIgn, &fEcxFeatures, &fEdxFeatures);
+ if (fEcxFeatures & X86_CPUID_FEATURE_ECX_HVP)
+ {
+ RTCCUINTREG const fOldFlags = ASMIntDisableFlags();
+ RTCCUINTXREG const fCr4 = ASMGetCR4();
+
+ RTCCUINTXREG const fSafeToClear = X86_CR4_TSD | X86_CR4_DE | X86_CR4_PGE | X86_CR4_PCE
+ | X86_CR4_FSGSBASE | X86_CR4_PCIDE | X86_CR4_SMEP | X86_CR4_SMAP
+ | X86_CR4_OSXSAVE | X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT;
+ RTCCUINTXREG fLoadCr4 = fCr4 & ~fSafeToClear;
+ RTCCUINTXREG const fCleared = fCr4 & fSafeToClear;
+ if (!(fCleared & X86_CR4_TSD) && (fEdxFeatures & X86_CPUID_FEATURE_EDX_TSC))
+ fLoadCr4 |= X86_CR4_TSD;
+ if (!(fCleared & X86_CR4_PGE) && (fEdxFeatures & X86_CPUID_FEATURE_EDX_PGE))
+ fLoadCr4 |= X86_CR4_PGE;
+ __try
+ {
+ ASMSetCR4(fLoadCr4);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ rc = VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT;
+ }
+ if (RT_SUCCESS(rc))
+ ASMSetCR4(fCr4);
+ ASMSetFlags(fOldFlags);
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+
#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
#define MY_SystemUnloadGdiDriverInformation 27
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
index 4e7d2d0..69e4d12 100644
--- a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
@@ -30,6 +30,8 @@
#include <VBoxNetFltNobjT_i.c>
+#include <Olectl.h>
+
//# define VBOXNETFLTNOTIFY_DEBUG_BIND
#ifdef DEBUG
@@ -583,22 +585,162 @@ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
return _Module.GetClassObject(rclsid, riid, ppv);
}
+/*
+ * ATL::CComModule does not suport server registration/unregistration methods,
+ * so we need to do it manually. Since this is the only place we do registraton
+ * manually, we do it the quick-and-dirty way.
+ */
+
+/* Someday we may want to log errors. */
+class AdHocRegError
+{
+public:
+ AdHocRegError(LSTATUS rc) { RT_NOREF1(rc); };
+};
+
+/* A simple wrapper on Windows registry functions. */
+class AdHocRegKey
+{
+public:
+ AdHocRegKey(HKEY hKey) : m_hKey(hKey) {};
+ AdHocRegKey(LPCWSTR pcwszName, HKEY hParent = HKEY_CLASSES_ROOT);
+ ~AdHocRegKey() { RegCloseKey(m_hKey); };
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey, LPCWSTR pcwszDefaultValue = NULL);
+ void remove(LPCWSTR pcwszSubkey);
+ void setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue);
+ HKEY getKey(void) { return m_hKey; };
+private:
+ HKEY m_hKey;
+};
+
+AdHocRegKey::AdHocRegKey(LPCWSTR pcwszName, HKEY hParent)
+{
+ LSTATUS rc = RegOpenKeyExW(hParent, pcwszName, 0, KEY_ALL_ACCESS, &m_hKey);
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+}
+
+void AdHocRegKey::remove(LPCWSTR pcwszSubkey)
+{
+ LSTATUS rc;
+ WCHAR wszName[256];
+ DWORD dwName;
+
+ /* Remove all subkeys of subkey first */
+ AdHocRegKey *subkey = new AdHocRegKey(pcwszSubkey, m_hKey);
+ for (;;)
+ {
+ /* Always ask for the first subkey, because we remove it before calling RegEnumKeyEx again */
+ dwName = 255;
+ rc = RegEnumKeyExW(subkey->getKey(), 0, wszName, &dwName, NULL, NULL, NULL, NULL);
+ if (rc != ERROR_SUCCESS)
+ break;
+ subkey->remove(wszName);
+ }
+ delete subkey;
+
+ /* Remove the subkey itself */
+ rc = RegDeleteKeyW(m_hKey, pcwszSubkey);
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+}
+
+AdHocRegKey *AdHocRegKey::create(LPCWSTR pcwszSubkey, LPCWSTR pcwszDefaultValue)
+{
+ HKEY hSubkey;
+ LSTATUS rc = RegCreateKeyExW(m_hKey, pcwszSubkey,
+ 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
+ KEY_ALL_ACCESS, NULL /*pSecAttr*/, &hSubkey, NULL /*pdwDisposition*/);
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+ AdHocRegKey *pSubkey = new AdHocRegKey(hSubkey);
+ if (pcwszDefaultValue)
+ pSubkey->setValue(NULL, pcwszDefaultValue);
+ return pSubkey;
+}
+
+void AdHocRegKey::setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+{
+ LSTATUS rc = RegSetValueExW(m_hKey, pcwszName, 0, REG_SZ, (const BYTE *)pcwszValue,
+ (DWORD)((wcslen(pcwszValue) + 1) * sizeof(WCHAR)));
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+}
+
+/*
+ * Auxiliary class that facilitates automatic destruction of AdHocRegKey objects
+ * allocated in heap. No reference counting here!
+ */
+class AdHocRegKeyPtr
+{
+public:
+ AdHocRegKeyPtr(AdHocRegKey *pKey) : m_pKey(pKey) {};
+ ~AdHocRegKeyPtr() { delete m_pKey; };
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey, LPCWSTR pcwszDefaultValue = NULL)
+ { return m_pKey->create(pcwszSubkey, pcwszDefaultValue); };
+ void remove(LPCWSTR pcwszSubkey)
+ { return m_pKey->remove(pcwszSubkey); };
+ void setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+ { return m_pKey->setValue(pcwszName, pcwszValue); };
+private:
+ AdHocRegKey *m_pKey;
+ /* Prevent copying, since we do not support reference counting */
+ AdHocRegKeyPtr(const AdHocRegKeyPtr&);
+ AdHocRegKeyPtr& operator=(const AdHocRegKeyPtr&);
+};
+
+
STDAPI DllRegisterServer()
{
-// this is a "just in case" conditional, which is not defined
-#ifdef VBOX_FORCE_REGISTER_SERVER
- return _Module.RegisterServer(TRUE);
-#else
+ WCHAR wszModule[MAX_PATH + 1];
+ if (GetModuleFileNameW(GetModuleHandleW(L"VBoxNetFltNobj"), wszModule, MAX_PATH) == 0)
+ return SELFREG_E_CLASS;
+
+ try {
+ AdHocRegKey keyCLSID(L"CLSID");
+ AdHocRegKeyPtr pkeyNobjClass(keyCLSID.create(L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}",
+ L"VirtualBox Bridged Networking Driver Notify Object v1.1"));
+ AdHocRegKeyPtr pkeyNobjSrv(pkeyNobjClass.create(L"InProcServer32", wszModule));
+ pkeyNobjSrv.setValue(L"ThreadingModel", L"Both");
+ }
+ catch (AdHocRegError)
+ {
+ return SELFREG_E_CLASS;
+ }
+
+ try {
+ AdHocRegKey keyTypeLib(L"TypeLib");
+ AdHocRegKeyPtr pkeyNobjLib(keyTypeLib.create(L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}\\1.1",
+ L"VirtualBox Bridged Networking Driver Notify Object v1.1 Type Library"));
+ AdHocRegKeyPtr pkeyNobjLib0(pkeyNobjLib.create(L"0\\win64", wszModule));
+ AdHocRegKeyPtr pkeyNobjLibFlags(pkeyNobjLib.create(L"FLAGS", L"0"));
+ if (GetSystemDirectoryW(wszModule, MAX_PATH) == 0)
+ return SELFREG_E_TYPELIB;
+ AdHocRegKeyPtr pkeyNobjLibHelpDir(pkeyNobjLib.create(L"HELPDIR", wszModule));
+ }
+ catch (AdHocRegError)
+ {
+ return SELFREG_E_CLASS;
+ }
+
return S_OK;
-#endif
}
STDAPI DllUnregisterServer()
{
-// this is a "just in case" conditional, which is not defined
-#ifdef VBOX_FORCE_REGISTER_SERVER
- return _Module.UnregisterServer(TRUE);
-#else
+ try {
+ AdHocRegKey keyTypeLib(L"TypeLib");
+ keyTypeLib.remove(L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}");
+ }
+ catch (AdHocRegError) { return SELFREG_E_TYPELIB; }
+
+ try {
+ AdHocRegKey keyCLSID(L"CLSID");
+ keyCLSID.remove(L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}");
+ }
+ catch (AdHocRegError) { return SELFREG_E_CLASS; }
+
return S_OK;
-#endif
}
diff --git a/src/VBox/HostServices/GuestProperties/service.cpp b/src/VBox/HostServices/GuestProperties/service.cpp
index 70c5054..b636e07 100644
--- a/src/VBox/HostServices/GuestProperties/service.cpp
+++ b/src/VBox/HostServices/GuestProperties/service.cpp
@@ -267,6 +267,28 @@ private:
}
/**
+ * Check whether the property name is reserved for host changes only.
+ *
+ * @returns Boolean true (host reserved) or false (available to guest).
+ *
+ * @param pszName The property name to check.
+ */
+ bool checkHostReserved(const char *pszName)
+ {
+ if (RTStrStartsWith(pszName, "/VirtualBox/GuestAdd/VBoxService/"))
+ return true;
+ if (RTStrStartsWith(pszName, "/VirtualBox/GuestAdd/PAM/"))
+ return true;
+ if (RTStrStartsWith(pszName, "/VirtualBox/GuestAdd/Greeter/"))
+ return true;
+ if (RTStrStartsWith(pszName, "/VirtualBox/GuestAdd/SharedFolders/"))
+ return true;
+ if (RTStrStartsWith(pszName, "/VirtualBox/HostInfo/"))
+ return true;
+ return false;
+ }
+
+ /**
* Gets a property.
*
* @returns Pointer to the property if found, NULL if not.
@@ -538,6 +560,11 @@ int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
uint32_t fFlags;
rc = validateFlags(papszFlags[i], &fFlags);
AssertRCBreak(rc);
+ /*
+ * Handle names which are read-only for the guest.
+ */
+ if (checkHostReserved(papszNames[i]))
+ fFlags |= RDONLYGUEST;
Property *pProp = getPropertyInternal(papszNames[i]);
if (pProp)
@@ -714,6 +741,16 @@ int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGues
*/
Property *pProp = getPropertyInternal(pcszName);
rc = checkPermission(pProp ? (ePropFlags)pProp->mFlags : NILFLAG, isGuest);
+ /*
+ * Handle names which are read-only for the guest.
+ */
+ if (rc == VINF_SUCCESS && checkHostReserved(pcszName))
+ {
+ if (isGuest)
+ rc = VERR_PERMISSION_DENIED;
+ else
+ fFlags |= RDONLYGUEST;
+ }
if (rc == VINF_SUCCESS)
{
/*
diff --git a/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp b/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
index 20b67d0..1fe0ade 100644
--- a/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
+++ b/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp
@@ -460,6 +460,11 @@ static void testSetProp(VBOXHGCMSVCFNTABLE *pTable)
{ "TEST NAME", "test", "", true, true, false },
{ "Green", "gone out...", "", false, false, false },
{ "Green", "gone out...", "", true, false, false },
+ { "/VirtualBox/GuestAdd/SharedFolders/MountDir", "test", "", false, true, false },
+ { "/VirtualBox/GuestAdd/SomethingElse", "test", "", false, true, true },
+ { "/VirtualBox/HostInfo/VRDP/Client/1/Name", "test", "", false, false, false },
+ { "/VirtualBox/GuestAdd/SharedFolders/MountDir", "test", "", true, true, true },
+ { "/VirtualBox/HostInfo/VRDP/Client/1/Name", "test", "TRANSRESET", true, true, true },
};
for (unsigned i = 0; i < RT_ELEMENTS(s_aSetProperties); ++i)
@@ -658,6 +663,12 @@ g_aGetNotifications[] =
{ "Amber\0Caution!\0", sizeof("Amber\0Caution!\0") },
{ "Green\0Go!\0READONLY", sizeof("Green\0Go!\0READONLY") },
{ "Blue\0What on earth...?\0", sizeof("Blue\0What on earth...?\0") },
+ { "/VirtualBox/GuestAdd/SomethingElse\0test\0",
+ sizeof("/VirtualBox/GuestAdd/SomethingElse\0test\0") },
+ { "/VirtualBox/GuestAdd/SharedFolders/MountDir\0test\0RDONLYGUEST",
+ sizeof("/VirtualBox/GuestAdd/SharedFolders/MountDir\0test\0RDONLYGUEST") },
+ { "/VirtualBox/HostInfo/VRDP/Client/1/Name\0test\0TRANSIENT, RDONLYGUEST, TRANSRESET",
+ sizeof("/VirtualBox/HostInfo/VRDP/Client/1/Name\0test\0TRANSIENT, RDONLYGUEST, TRANSRESET") },
{ "Red\0\0", sizeof("Red\0\0") },
{ "Amber\0\0", sizeof("Amber\0\0") },
};
diff --git a/src/VBox/HostServices/SharedFolders/vbsf.cpp b/src/VBox/HostServices/SharedFolders/vbsf.cpp
index 32f509c..830ffa4 100644
--- a/src/VBox/HostServices/SharedFolders/vbsf.cpp
+++ b/src/VBox/HostServices/SharedFolders/vbsf.cpp
@@ -1525,9 +1525,13 @@ static int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Ha
#ifndef RT_OS_WINDOWS
/* Don't allow the guest to clear the own bit, otherwise the guest wouldn't be
- * able to access this file anymore. Only for guests, which set the UNIX mode. */
+ * able to access this file anymore. Only for guests, which set the UNIX mode.
+ * Also, clear bits which we don't pass through for security reasons. */
if (fMode & RTFS_UNIX_MASK)
+ {
fMode |= RTFS_UNIX_IRUSR;
+ fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
+ }
#endif
rc = RTFileSetMode(pHandle->file.Handle, fMode);
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.pyc b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.pyc
index 750e26f..6389c52 100644
Binary files a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.pyc and b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.pyc differ
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
index 3cc473f..dfd591e 100644
--- a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
@@ -246,6 +246,7 @@ typedef struct {
int force_direct;
int sync;
#endif
+ int force_present_main_thread;
int render_to_app_window;
int render_to_crut_window;
int crut_drawable;
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
index b3ebf7a..dd1f0a1 100644
--- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
@@ -115,14 +115,11 @@
/** @def FBO
* Disable this to see how the output is without the FBO in the middle of the processing chain. */
#define FBO 1
-/** @def CR_RENDER_FORCE_PRESENT_MAIN_THREAD
- * Force present schedule to main thread. */
/** @def SHOW_WINDOW_BACKGROUND
* Define this to see the window background even if the window is clipped. */
/** @def DEBUG_VERBOSE
* Define this to get some debug info about the messages flow. */
#if 0 || defined(DOXYGEN_RUNNING)
-# define CR_RENDER_FORCE_PRESENT_MAIN_THREAD
# define SHOW_WINDOW_BACKGROUND 1
# define DEBUG_VERBOSE
#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
index 49d745a..624a051 100644
--- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
@@ -372,5 +372,21 @@ void renderspuSetVBoxConfiguration( RenderSPU *render_spu )
#if defined(GLX)
render_spu->sync = 0;
#endif
+
+ /* Config of "render force present main thread" (currently implemented by glx and wgl). */
+ {
+ const char *forcePresent = crGetenv("CR_RENDER_FORCE_PRESENT_MAIN_THREAD");
+ if (forcePresent)
+ render_spu->force_present_main_thread = crStrToInt(forcePresent) ? 1 : 0;
+ else
+ {
+#if defined(GLX)
+ /* Customer needed this for avoiding system 3D driver bugs. */
+ render_spu->force_present_main_thread = 1;
+#else
+ render_spu->force_present_main_thread = 0;
+#endif
+ }
+ }
}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
index 6d935f0..8a1a61f 100644
--- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
@@ -1924,25 +1924,31 @@ renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
}
}
-#define CR_RENDER_FORCE_PRESENT_MAIN_THREAD
-
void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
{
- /* the CR_RENDER_FORCE_PRESENT_MAIN_THREAD is actually inherited from cocoa backend impl,
- * here it forces rendering in WinCmd thread rather than a Main thread.
- * it is used for debugging only in any way actually.
- * @todo: change to some more generic macro name */
-#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
- const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
- /* we do not want to be blocked with the GUI thread here, so only draw her eif we are really able to do that w/o bllocking */
- int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
- if (RT_SUCCESS(rc))
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WinCmd thread rather
+ * than a Main thread. It defaults to 1, because otherwise there were
+ * 3D driver incompatibilities on some systems. Elsewhere it causes flicker
+ * on NVidia GPUs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
{
- renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
- renderspuVBoxCompositorRelease(window);
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ WARN(("renderspuVBoxCompositorTryAcquire failed rc %d", rc));
+ return;
+ }
}
- else if (rc == VERR_SEM_BUSY)
-#endif
+
{
Status status;
XEvent event;
@@ -1961,13 +1967,6 @@ void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VB
}
XFlush(render_spu.pCommunicationDisplay);
}
-#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
- else
- {
- /* this is somewhat we do not expect */
- WARN(("renderspuVBoxCompositorTryAcquire failed rc %d", rc));
- }
-#endif
}
static void
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
index 9c87091..e93aa53 100644
--- a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
@@ -1284,33 +1284,32 @@ void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
{
- /* the CR_RENDER_FORCE_PRESENT_MAIN_THREAD is actually inherited from cocoa backend impl,
- * here it forces rendering in WinCmd thread rather than a Main thread.
- * it is used for debugging only in any way actually.
- * @todo: change to some more generic macro name */
-#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
- const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
- /* we do not want to be blocked with the GUI thread here, so only draw her eif we are really able to do that w/o bllocking */
- int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
- if (RT_SUCCESS(rc))
- {
- renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
- renderspuVBoxCompositorRelease(window);
- }
- else if (rc == VERR_SEM_BUSY)
-#endif
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WndProc, i.e. main
+ * thread. It defaults to 0, because it is for debugging and working around
+ * bugs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc);
+ }
+ }
+
{
render_spu.self.Flush();
renderspuVBoxPresentBlitterEnsureCreated(window, 0);
RedrawWindow(window->hWnd, NULL, NULL, RDW_INTERNALPAINT);
}
-#ifndef CR_RENDER_FORCE_PRESENT_MAIN_THREAD
- else
- {
- /* this is somewhat we do not expect */
- crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc);
- }
-#endif
}
GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
diff --git a/src/VBox/Installer/Config.kmk b/src/VBox/Installer/Config.kmk
index bd22d39..4bbcb49 100644
--- a/src/VBox/Installer/Config.kmk
+++ b/src/VBox/Installer/Config.kmk
@@ -62,6 +62,9 @@ ifdef VBOX_WITH_UNATTENDED
ubuntu_preseed.cfg \
fedora_ks.cfg \
ol_ks.cfg \
+ rhel3_ks.cfg \
+ rhel4_ks.cfg \
+ rhel5_ks.cfg \
redhat67_ks.cfg \
win_nt5_unattended.sif \
win_nt6_unattended.xml \
diff --git a/src/VBox/Installer/linux/routines.sh b/src/VBox/Installer/linux/routines.sh
index 57027ca..98ce607 100644
--- a/src/VBox/Installer/linux/routines.sh
+++ b/src/VBox/Installer/linux/routines.sh
@@ -93,6 +93,15 @@ check_root()
fi
}
+## Abort if dependencies are not found
+check_deps()
+{
+ for i in ${@}; do
+ type "${i}" >/dev/null 2>&1 ||
+ abort "${i} not found. Please install: ${*}; and try again."
+ done
+}
+
## Abort if a copy of VirtualBox is already running
check_running()
{
diff --git a/src/VBox/Installer/win/Makefile.kmk b/src/VBox/Installer/win/Makefile.kmk
index a2998df..cc784aa 100644
--- a/src/VBox/Installer/win/Makefile.kmk
+++ b/src/VBox/Installer/win/Makefile.kmk
@@ -185,9 +185,10 @@ ifdef VBOX_WITH_COMBINED_PACKAGE
OTHER_CLEAN += \
$(PATH_STAGE_BIN)/$(PACKAGE_NAME_MULTIARCH_FINAL) \
$(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.x86)
- else
+ endif
+ ifndef VBOX_WITH_MSM_INSTALL
OTHER_CLEAN += \
- $(PACKAGE_NAME_MULTIARCH_COMMONCAB)
+ $(VBOX_WIN_INST_OUT_DIR)/common.cab
endif
else
OTHER_CLEAN += \
@@ -387,7 +388,7 @@ endif
#
define def_vbox_link_msi
$(VBOX_WIN_INST_OUT_DIR)/$(lang)/$(PACKAGE_NAME_LANG)_$(lang).msi \
-$(if-expr defined(VBOX_WITH_COMBINED_PACKAGE), + $(VBOX_WIN_INST_OUT_DIR)/common.cab,): \
+$(if-expr defined(VBOX_WITH_COMBINED_PACKAGE) && !defined(VBOX_WITH_MSM_INSTALL), + $(VBOX_WIN_INST_OUT_DIR)/common.cab,): \
$(VBOX_WIN_INST_OUT_DIR)/$(lang)/VirtualBox_$(lang).wixobj \
$(VBOX_WIN_INST_OUT_DIR)/NLS/Language_$(lang).wxl \
$(VBOX_WIN_INST_OUT_DIR)/NLS/License_$(lang).wxl \
@@ -409,7 +410,7 @@ $(if-expr defined(VBOX_WITH_COMBINED_PACKAGE), + $(VBOX_WIN_INST_OUT_DIR)/common
-out $$@ \
$$< \
$(VBOX_PATH_WIX)/difxapp_$(if-expr "$(KBUILD_TARGET_ARCH)" == "x86",x86,x64).wixlib
-ifdef VBOX_WITH_COMBINED_PACKAGE
+if defined(VBOX_WITH_COMBINED_PACKAGE) && !defined(VBOX_WITH_MSM_INSTALL)
$(MV) -f -- $$(@D)/common.cab $$(@D)/../common.cab
endif
endef
@@ -446,7 +447,7 @@ $(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).msm: \
$(call VBOX_SIGN_FILE_FN,$$@,$(VBOX_PRODUCT) $(VBOX_VERSION_STRING)r$(VBOX_SVN_REV) ($(KBUILD_TARGET_ARCH)),,,disable-dual-signing)
endef
-$(if $(VBOX_WITH_MSM_INSTALL), \
+$(if-expr defined(VBOX_WITH_MSM_INSTALL), \
$(foreach module,$(VBOX_INSTALLER_MERGE_MODULES), \
$(foreach lang,$(VBOX_INSTALLER_MERGE_LANGUAGES), \
$(eval $(def_vbox_link_msm)))),)
@@ -489,7 +490,7 @@ includedep $(VBOX_WIN_INST_OUT_DIR)/$(lang)/VirtualBox_$(lang).wixobj.dep
$(VBOX_WIN_INST_OUT_DIR)/$(lang)/VirtualBox_$(lang).wixobj: \
$(PATH_SUB_CURRENT)/VirtualBox.wxs \
$(PATH_SUB_CURRENT)/UserInterface.wxi \
- $(if $(VBOX_WITH_MSM_INSTALL), \
+ $(if-expr defined(VBOX_WITH_MSM_INSTALL), \
$(foreach module,$(VBOX_INSTALLER_MERGE_MODULES), \
$(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).msm), \
$(VBOX_WIN_INST_OUT_DIR)/Shortcuts_StartMenu.wxi \
@@ -527,14 +528,14 @@ $(VBOX_WIN_INST_OUT_DIR)/$(lang)/VirtualBox_$(lang).wixobj: \
-E 'VBOX_CAB_COMPRESSION_LEVEL_COMMON=$(if-expr $(lang) == "en_US" && $(KBUILD_TARGET_ARCH) == "amd64",$(VBOX_CAB_COMPRESSION_LEVEL),none)' \
-E 'VBOX_GUI_USE_QGL=$(if $(VBOX_GUI_USE_QGL),yes,no)' \
-E 'VBOX_MIDL_PROXY_CLSID=$(VBOX_MIDL_PROXY_CLSID)' \
- $(if $(VBOX_WITH_MSM_INSTALL), \
+ $(if-expr defined(VBOX_WITH_MSM_INSTALL), \
$(foreach module,$(VBOX_INSTALLER_MERGE_MODULES), \
-E 'VBOX_WIN_INST_MERGE_$(toupper $(module))=$(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).msm'),) \
-E 'VBOX_WINDOWS_ICON_FILE=$(subst /,\,$(VBOX_WINDOWS_ICON_FILE))' \
-E 'VBOX_QT_INFIX=$(VBOX_QT_INFIX)' \
-E 'VBOX_WITH_32_ON_64_MAIN_API=$(if $(VBOX_WITH_32_ON_64_MAIN_API),yes,no)' \
-E 'VBOX_WITH_ADDITIONS_PACKING=$(if $(VBOX_WITH_ADDITIONS_PACKING),yes,no)' \
- -E 'VBOX_WITH_COMBINED_PACKAGE=$(if $(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \
+ -E 'VBOX_WITH_COMBINED_PACKAGE=$(if-expr defined(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \
-E 'VBOX_WITH_CROGL=$(if $(VBOX_WITH_CROGL),yes,no)' \
-E 'VBOX_WITH_DEBUGGER_GUI=$(if-expr defined(VBOX_WITH_DEBUGGER_GUI) && defined(VBOX_WITH_QTGUI),yes,no)' \
-E 'VBOX_WITH_DOCS_PACKING=$(if $(VBOX_WITH_DOCS_PACKING),yes,no)' \
@@ -547,7 +548,7 @@ $(VBOX_WIN_INST_OUT_DIR)/$(lang)/VirtualBox_$(lang).wixobj: \
-E 'VBOX_WITH_HARDENING=$(if $(VBOX_WITH_HARDENING),yes,no)' \
-E 'VBOX_WITH_LICENSE_DISPLAY=$(if $(VBOX_WITH_LICENSE_DISPLAY),yes,no)' \
-E 'VBOX_WITH_MIDL_PROXY_STUB=$(if $(VBOX_WITH_MIDL_PROXY_STUB),yes,no)' \
- -E 'VBOX_WITH_MSM_INSTALL=$(if $(VBOX_WITH_MSM_INSTALL),yes,no)' \
+ -E 'VBOX_WITH_MSM_INSTALL=$(if-expr defined(VBOX_WITH_MSM_INSTALL),yes,no)' \
-E 'VBOX_WITH_NETFLT=$(if $(VBOX_WITH_NETFLT),yes,no)' \
-E 'VBOX_WITH_PYTHON=$(if $(VBOX_WITH_PYTHON),yes,no)' \
-E 'VBOX_WITH_QTGUI=$(if $(VBOX_WITH_QTGUI),yes,no)' \
@@ -626,7 +627,7 @@ $(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).wixobj: \
-E 'VBOX_QT_INFIX=$(VBOX_QT_INFIX)' \
-E 'VBOX_WITH_32_ON_64_MAIN_API=$(if $(VBOX_WITH_32_ON_64_MAIN_API),yes,no)' \
-E 'VBOX_WITH_ADDITIONS_PACKING=$(if $(VBOX_WITH_ADDITIONS_PACKING),yes,no)' \
- -E 'VBOX_WITH_COMBINED_PACKAGE=$(if $(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \
+ -E 'VBOX_WITH_COMBINED_PACKAGE=$(if-expr defined(VBOX_WITH_COMBINED_PACKAGE),yes,no)' \
-E 'VBOX_WITH_CROGL=$(if $(VBOX_WITH_CROGL),yes,no)' \
-E 'VBOX_WITH_DEBUGGER_GUI=$(if-expr defined(VBOX_WITH_DEBUGGER_GUI) && defined(VBOX_WITH_QTGUI),yes,no)' \
-E 'VBOX_WITH_DOCS_PACKING=$(if $(VBOX_WITH_DOCS_PACKING),yes,no)' \
@@ -639,7 +640,7 @@ $(VBOX_WIN_INST_OUT_DIR)/VBoxMerge$(module)_$(lang).wixobj: \
-E 'VBOX_WITH_HARDENING=$(if $(VBOX_WITH_HARDENING),yes,no)' \
-E 'VBOX_WITH_LICENSE_DISPLAY=$(if $(VBOX_WITH_LICENSE_DISPLAY),yes,no)' \
-E 'VBOX_WITH_MIDL_PROXY_STUB=$(if $(VBOX_WITH_MIDL_PROXY_STUB),yes,no)' \
- -E 'VBOX_WITH_MSM_INSTALL=$(if $(VBOX_WITH_MSM_INSTALL),yes,no)' \
+ -E 'VBOX_WITH_MSM_INSTALL=$(if-expr defined(VBOX_WITH_MSM_INSTALL),yes,no)' \
-E 'VBOX_WITH_NETFLT=$(if $(VBOX_WITH_NETFLT),yes,no)' \
-E 'VBOX_WITH_PYTHON=$(if $(VBOX_WITH_PYTHON),yes,no)' \
-E 'VBOX_WITH_QTGUI=$(if $(VBOX_WITH_QTGUI),yes,no)' \
@@ -821,12 +822,12 @@ $(PATH_STAGE_BIN)/$(PACKAGE_NAME_MULTIARCH_FINAL): \
$(PATH_STAGE_BIN)/VBoxStub.exe \
$$(VBoxStubBld_1_TARGET)
$(call MSG_L1,Building Windows combined package)
- $(if $(VBOX_WITH_MSM_INSTALL),,$(call VBOX_SIGN_FILE_FN,$(PACKAGE_NAME_MULTIARCH_COMMONCAB)))
+ $(if-expr defined(VBOX_WITH_MSM_INSTALL),,$(call VBOX_SIGN_FILE_FN,$(PACKAGE_NAME_MULTIARCH_COMMONCAB)))
$(REDIRECT) -C $(@D) -- \
$(VBoxStubBld_1_TARGET) -out $@ \
-target-x86 $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.x86) \
-target-amd64 $(PATH_MULTIARCH_TEMP)/$(PACKAGE_NAME_MULTIARCH.amd64) \
- $(if $(VBOX_WITH_MSM_INSTALL),,-target-all $(PACKAGE_NAME_MULTIARCH_COMMONCAB)) \
+ $(if-expr defined(VBOX_WITH_MSM_INSTALL),,-target-all $(PACKAGE_NAME_MULTIARCH_COMMONCAB)) \
-stub $(PATH_STAGE_BIN)/VBoxStub.exe
$(VBOX_VCC_EDITBIN) /IntegrityCheck:NO $@
$(call VBOX_SIGN_FILE_FN,$@)
diff --git a/src/VBox/Installer/win/VirtualBox.wxs b/src/VBox/Installer/win/VirtualBox.wxs
index 5ad577d..3fe9dfb 100644
--- a/src/VBox/Installer/win/VirtualBox.wxs
+++ b/src/VBox/Installer/win/VirtualBox.wxs
@@ -431,12 +431,12 @@
<?if $(env.VBOX_WITH_32_ON_64_MAIN_API) = "yes" ?>
<ComponentRef Id="cp_MainCOM_x86" />
<?endif ?>
- <ComponentRef Id="cp_MainCOM" />
+ <ComponentRef Id="cp_MainCOM" />
<?if $(env.VBOX_WITH_MIDL_PROXY_STUB) = "yes" ?>
<ComponentRef Id="cp_ProxyStub" />
<ComponentRef Id="cp_ProxyStubLegacy" />
<?endif?>
- <ComponentRef Id="cp_MainBinaries" />
+ <ComponentRef Id="cp_MainBinaries" />
<?if $(env.VBOX_WITH_QTGUI) = "yes" ?>
<ComponentRef Id="cp_QtPlatforms" />
<?endif ?>
@@ -448,17 +448,16 @@
<?if $(env.VBOX_WITH_CROGL) = "yes" ?>
<ComponentRef Id="cp_VBoxCROpenGL" />
<?endif ?>
- <ComponentRef Id="cp_VBoxSDLBinaries" />
+ <ComponentRef Id="cp_VBoxSDLBinaries" />
<?if $(env.VBOX_WITH_WEBSERVICES) = "yes" ?>
<ComponentRef Id="cp_VBoxWebService" />
<?endif ?>
- <ComponentRef Id="cp_VBoxCAPI" />
- <ComponentRef Id="cp_VBoxDrv" />
-<?endif ?>
-
-<?if $(env.VBOX_WITH_UNATTENDED) = "yes" ?>
+ <ComponentRef Id="cp_VBoxCAPI" />
+ <?if $(env.VBOX_WITH_UNATTENDED) = "yes" ?>
<!-- unattended template component -->
<ComponentRef Id="cp_UnattendedTemplates" />
+ <?endif ?>
+ <ComponentRef Id="cp_VBoxDrv" />
<?endif ?>
<Feature Id="VBoxUSB" Title="VirtualBox USB Support" Level="1"
diff --git a/src/VBox/Main/UnattendedTemplates/Makefile.kmk b/src/VBox/Main/UnattendedTemplates/Makefile.kmk
index 5e06e90..44e99bb 100644
--- a/src/VBox/Main/UnattendedTemplates/Makefile.kmk
+++ b/src/VBox/Main/UnattendedTemplates/Makefile.kmk
@@ -28,6 +28,9 @@ ifdef VBOX_WITH_UNATTENDED
VBoxUnattendedTemplates_SOURCES = \
debian_preseed.cfg \
ubuntu_preseed.cfg \
+ rhel3_ks.cfg \
+ rhel4_ks.cfg \
+ rhel5_ks.cfg \
redhat67_ks.cfg \
ol_ks.cfg \
fedora_ks.cfg \
diff --git a/src/VBox/Main/UnattendedTemplates/debian_postinstall.sh b/src/VBox/Main/UnattendedTemplates/debian_postinstall.sh
index f727999..0e7939c 100755
--- a/src/VBox/Main/UnattendedTemplates/debian_postinstall.sh
+++ b/src/VBox/Main/UnattendedTemplates/debian_postinstall.sh
@@ -234,15 +234,15 @@ if [ -d "${MY_UNIT_PATH}" ]; then
log_command_in_target systemctl -q enable vboxtxs
# System V like:
-elif [ -e /etc/init.d/ ]; then
+elif [ -e "${MY_TARGET}/etc/init.d/" ]; then
# Install the script. On rhel6 scripts are under /etc/rc.d/ with /etc/init.d and /etc/rc?.d being symlinks.
- if [ -d /etc/rc.d/init.d/ ]; then
- MY_INIT_D_PATH="${MY_TARGET}/etc/rc.d"
- log_command ln -s "../../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PATH}/init.d/"
+ if [ -d "${MY_TARGET}/etc/rc.d/init.d/" ]; then
+ MY_INIT_D_PARENT_PATH="${MY_TARGET}/etc/rc.d"
+ log_command ln -s "../../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PARENT_PATH}/init.d/"
else
- MY_INIT_D_PATH="${MY_TARGET}/etc"
- log_command ln -s "../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PATH}/init.d/"
+ MY_INIT_D_PARENT_PATH="${MY_TARGET}/etc"
+ log_command ln -s "../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PARENT_PATH}/init.d/"
fi
# Use runlevel management script if found.
@@ -256,13 +256,13 @@ elif [ -e /etc/init.d/ ]; then
log_command_in_target rc-update add vboxtxs default
# Fall back on hardcoded symlinking.
else
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc0.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc1.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc6.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc2.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc3.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc4.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc5.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc0.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc1.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc6.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc2.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc3.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc4.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc5.d/S35vboxtxs"
fi
else
echo "** error: Unknown init script system." | tee -a "${MY_LOGFILE}"
diff --git a/src/VBox/Main/UnattendedTemplates/redhat_postinstall.sh b/src/VBox/Main/UnattendedTemplates/redhat_postinstall.sh
index 4a6f9f9..538d9f4 100755
--- a/src/VBox/Main/UnattendedTemplates/redhat_postinstall.sh
+++ b/src/VBox/Main/UnattendedTemplates/redhat_postinstall.sh
@@ -78,7 +78,7 @@ log_command()
echo "** Date: `date -R`" >> "${MY_LOGFILE}"
echo "** Executing: $*" >> "${MY_LOGFILE}"
"$@" 2>&1 | tee -a "${MY_LOGFILE}"
- MY_TMP_EXITCODE="${PIPESTATUS[0]}"
+ MY_TMP_EXITCODE="${PIPESTATUS[0]}" # bashism - whatever.
if [ "${MY_TMP_EXITCODE}" != "0" ]; then
if [ "${MY_TMP_EXITCODE}" != "${MY_IGNORE_EXITCODE}" ]; then
echo "** exit code: ${MY_TMP_EXITCODE}" | tee -a "${MY_LOGFILE}"
@@ -214,15 +214,15 @@ if [ -d "${MY_UNIT_PATH}" ]; then
log_command_in_target systemctl -q enable vboxtxs
# System V like:
-elif [ -e /etc/init.d/ ]; then
+elif [ -e "${MY_TARGET}/etc/init.d/" ]; then
# Install the script. On rhel6 scripts are under /etc/rc.d/ with /etc/init.d and /etc/rc?.d being symlinks.
- if [ -d /etc/rc.d/init.d/ ]; then
- MY_INIT_D_PATH="${MY_TARGET}/etc/rc.d"
- log_command ln -s "../../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PATH}/init.d/"
+ if [ -d "${MY_TARGET}/etc/rc.d/init.d/" ]; then
+ MY_INIT_D_PARENT_PATH="${MY_TARGET}/etc/rc.d"
+ log_command ln -s "../../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PARENT_PATH}/init.d/"
else
- MY_INIT_D_PATH="${MY_TARGET}/etc"
- log_command ln -s "../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PATH}/init.d/"
+ MY_INIT_D_PARENT_PATH="${MY_TARGET}/etc"
+ log_command ln -s "../../opt/validationkit/linux/vboxtxs" "${MY_INIT_D_PARENT_PATH}/init.d/"
fi
# Use runlevel management script if found.
@@ -236,13 +236,13 @@ elif [ -e /etc/init.d/ ]; then
log_command_in_target rc-update add vboxtxs default
# Fall back on hardcoded symlinking.
else
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc0.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc1.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc6.d/K65vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc2.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc3.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc4.d/S35vboxtxs"
- log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PATH}/rc5.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc0.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc1.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc6.d/K65vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc2.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc3.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc4.d/S35vboxtxs"
+ log_command ln -s "../init.d/vboxtxs" "${MY_INIT_D_PARENT_PATH}/rc5.d/S35vboxtxs"
fi
else
echo "** error: Unknown init script system." | tee -a "${MY_LOGFILE}"
diff --git a/src/VBox/Main/UnattendedTemplates/rhel3_ks.cfg b/src/VBox/Main/UnattendedTemplates/rhel3_ks.cfg
new file mode 100644
index 0000000..797737a
--- /dev/null
+++ b/src/VBox/Main/UnattendedTemplates/rhel3_ks.cfg
@@ -0,0 +1,141 @@
+#
+# Template for RHEL3 and derivatives.
+#
+# Note! RHEL3 kickstart typically just hangs if it finds something it doesn't like.
+# So, all changes to this file must be tested!
+#
+# N.B! AHCI is not supported by RHEL3
+#
+
+# Use text mode install
+text
+
+# Install OS instead of upgrade
+install
+
+# System language
+lang @@VBOX_INSERT_LOCALE@@.UTF-8
+
+# rhel4+rhel3 needs:
+langsupport --default @@VBOX_INSERT_LOCALE@@.UTF-8 @@VBOX_INSERT_LOCALE@@.UTF-8
+
+# Use CDROM installation media
+cdrom
+
+# System authorization information (rhel5: no --passalgo=sha512)
+#auth --useshadow
+authconfig --enableshadow --enablemd5
+
+# Root password (rhel5 not --plaintext groks)
+rootpw @@VBOX_INSERT_ROOT_PASSWORD_SH@@
+
+# Network information
+# rhel3: doesn't like --onboot=on.
+network --bootproto=dhcp --device=eth0 --hostname=@@VBOX_INSERT_HOSTNAME_FQDN_SH@@
+
+# Firewall configuration
+firewall --disabled
+
+# System keyboard
+keyboard us
+
+# rhel3 wants mouse config.
+mouse genericwheelps/2 --device psaux
+
+@@VBOX_COND_IS_NOT_MINIMAL_INSTALLATION@@
+# rhel3 wants xconfig.
+# TODO: Dunno VRAM size, is that a problem? --videoram 32768
+xconfig --card "VESA driver (generic)" --hsync 31.5-37.9 --vsync 50-70 --resolution 800x600 --depth 24 --startxonboot --defaultdesktop gnome
+@@VBOX_COND_END@@
+
+# SELinux configuration
+# rhel3: disable selinux
+# selinux --enforcing
+
+# Installation logging level
+#rhel4 does not grok: logging --level=info
+
+# System timezone
+timezone@@VBOX_COND_IS_RTC_USING_UTC@@ --utc@@VBOX_COND_END@@ @@VBOX_INSERT_TIME_ZONE_UX@@
+
+# System bootloader configuration
+bootloader --location=mbr --append="nomodeset crashkernel=auto rhgb quiet"
+zerombr
+
+# Partition clearing information
+clearpart --all --initlabel
+
+# Disk partitioning information (rhel5: no ext4, so use ext3)
+part / --fstype ext3 --size 6000 --grow --asprimary
+part swap --size 1024
+
+#Initial user
+#rhel4 does not grok, done in welcome sequence: user --name=@@VBOX_INSERT_USER_LOGIN_SH@@ --password=@@VBOX_INSERT_USER_PASSWORD_SH@@
+
+# Reboot after installation
+# Note! Not sure exctly when the --eject option was added. Need to find out an make it optional.
+reboot --eject
+
+# Packages. We currently ignore missing packages/groups here to keep things simpler.
+%packages --ignoremissing
+grub
+kernel
+@ base
+@ core
+@@VBOX_COND_IS_NOT_MINIMAL_INSTALLATION@@
+@ admin-tools
+@ development
+@ editors
+@ text-internet
+@ base-x
+@ graphics
+@ basic-desktop
+@ general-desktop
+@ gnome-desktop
+@ desktop-platform
+@ fonts
+@ graphical-admin-tools
+@ graphical-internet
+@ remote-desktop-clients
+@ sound-and-video
+@ x11
+@@VBOX_COND_END@@
+
+# Prepare building the additions kernel module, try get what we can from the cdrom as it may be impossible
+# to install anything from the post script (rhel3 seems to need kernel-sources):
+kernel-source
+kernel-headers
+kernel-devel
+glibc-devel
+glibc-headers
+gcc
+dkms
+make
+bzip2
+perl
+# %end - rhel5 does not like this.
+
+
+# Pre install script for mounting the cdrom, to make sure it cannot be ejcted.
+# See https://bugzilla.redhat.com/show_bug.cgi?id=239002
+%pre
+mkdir -p /tmp/vboxcdrom
+mount -t iso9660 /tmp/cdrom /tmp/vboxcdrom || mount -t iso9660 /dev/hdc /tmp/vboxcdrom || mount -t iso9660 /dev/scd0 /tmp/vboxcdrom || mount -t iso9660 /dev/sdb /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
+
+# Post install happens in a different script.
+# Note! We mount the CDROM explictily here since the location differs between fedora 26 to rhel5
+# and apparently there isn't any way to be certain that anaconda didn't unmount it already.
+# rhel5: There is not /bin/bash, so use /bin/sh
+# rhel5: There is no /dev/cdrom, so try use /dev/hdc and /dev/sdb.
+# rhel3: no --log option
+%post --nochroot
+df -h
+cp /tmp/vboxcdrom/vboxpostinstall.sh /mnt/sysimage/root/vboxpostinstall.sh
+chmod a+x /mnt/sysimage/root/vboxpostinstall.sh
+/bin/sh /mnt/sysimage/root/vboxpostinstall.sh --rhel
+umount /tmp/vboxcdrom
+rmdir /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
diff --git a/src/VBox/Main/UnattendedTemplates/rhel4_ks.cfg b/src/VBox/Main/UnattendedTemplates/rhel4_ks.cfg
new file mode 100644
index 0000000..54a2cda
--- /dev/null
+++ b/src/VBox/Main/UnattendedTemplates/rhel4_ks.cfg
@@ -0,0 +1,120 @@
+# Template for RHEL5 and derivatives.
+#platform=x86, AMD64, or Intel EM64T
+#version=DEVEL
+
+# Firewall configuration
+firewall --disabled
+
+# Install OS instead of upgrade
+install
+
+# Use CDROM installation media
+cdrom
+
+# Root password (rhel5 not --plaintext groks)
+rootpw @@VBOX_INSERT_ROOT_PASSWORD_SH@@
+
+# System authorization information (rhel5: no --passalgo=sha512)
+auth --useshadow
+
+# Use text mode install
+text
+
+# System keyboard
+keyboard us
+
+# System language
+lang @@VBOX_INSERT_LOCALE@@
+# rhel4 needs:
+langsupport --default=@@VBOX_INSERT_LOCALE@@.UTF-8 @@VBOX_INSERT_LOCALE@@.UTF-8
+
+
+# SELinux configuration
+selinux --enforcing
+
+# Installation logging level
+#rhel4 does not grok: logging --level=info
+
+# System timezone
+timezone@@VBOX_COND_IS_RTC_USING_UTC@@ --utc@@VBOX_COND_END@@ @@VBOX_INSERT_TIME_ZONE_UX@@
+
+# Network information
+network --bootproto=dhcp --device=eth0 --onboot=on --hostname=@@VBOX_INSERT_HOSTNAME_FQDN_SH@@
+
+# System bootloader configuration
+bootloader --location=mbr --append="nomodeset crashkernel=auto rhgb quiet"
+zerombr
+
+# Partition clearing information
+clearpart --all --initlabel
+
+# Disk partitioning information (rhel5: no ext4, so use ext3)
+part / --fstype ext3 --size 6000 --grow --asprimary
+part swap --size 1024
+
+#Initial user
+#rhel4 does not grok, done in welcome sequence: user --name=@@VBOX_INSERT_USER_LOGIN_SH@@ --password=@@VBOX_INSERT_USER_PASSWORD_SH@@
+
+# Reboot after installation
+# Note! Not sure exctly when the --eject option was added. Need to find out an make it optional.
+reboot --eject
+
+# Packages. We currently ignore missing packages/groups here to keep things simpler.
+%packages --ignoremissing
+@ base
+@ core
+@@VBOX_COND_IS_NOT_MINIMAL_INSTALLATION@@
+@ admin-tools
+@ development
+@ editors
+@ text-internet
+@ base-x
+@ graphics
+@ basic-desktop
+@ general-desktop
+@ gnome-desktop
+@ desktop-platform
+@ fonts
+@ graphical-admin-tools
+@ graphical-internet
+@ remote-desktop-clients
+@ sound-and-video
+@ x11
+@@VBOX_COND_END@@
+
+# Prepare building the additions kernel module, try get what we can from the cdrom as it may be impossible
+# to install anything from the post script:
+kernel-headers
+kernel-devel
+glibc-devel
+glibc-headers
+gcc
+dkms
+make
+bzip2
+perl
+# %end - rhel5 does not like this.
+
+
+# Pre install script for mounting the cdrom, to make sure it cannot be ejcted.
+# See https://bugzilla.redhat.com/show_bug.cgi?id=239002
+%pre
+mkdir -p /tmp/vboxcdrom
+mount -t iso9660 /tmp/cdrom /tmp/vboxcdrom || mount -t iso9660 /dev/hdc /tmp/vboxcdrom || mount -t iso9660 /dev/scd0 /tmp/vboxcdrom || mount -t iso9660 /dev/sdb /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
+
+# Post install happens in a different script.
+# Note! We mount the CDROM explictily here since the location differs between fedora 26 to rhel5
+# and apparently there isn't any way to be certain that anaconda didn't unmount it already.
+# rhel5: There is not /bin/bash, so use /bin/sh
+# rhel5: There is no /dev/cdrom, so try use /dev/hdc and /dev/sdb.
+%post --nochroot --log=/mnt/sysimage/root/ks-post.log
+df -h 1>&2
+cp /tmp/vboxcdrom/vboxpostinstall.sh /mnt/sysimage/root/vboxpostinstall.sh
+chmod a+x /mnt/sysimage/root/vboxpostinstall.sh
+/bin/sh /mnt/sysimage/root/vboxpostinstall.sh --rhel
+umount /tmp/vboxcdrom
+rmdir /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
diff --git a/src/VBox/Main/UnattendedTemplates/rhel5_ks.cfg b/src/VBox/Main/UnattendedTemplates/rhel5_ks.cfg
new file mode 100644
index 0000000..67bc998
--- /dev/null
+++ b/src/VBox/Main/UnattendedTemplates/rhel5_ks.cfg
@@ -0,0 +1,119 @@
+# Template for RHEL5 and derivatives.
+#platform=x86, AMD64, or Intel EM64T
+#version=DEVEL
+
+# Firewall configuration
+firewall --disabled
+
+# Install OS instead of upgrade
+install
+
+# Use CDROM installation media
+cdrom
+
+# Root password (rhel5 not --plaintext groks)
+rootpw @@VBOX_INSERT_ROOT_PASSWORD_SH@@
+
+# System authorization information (rhel5: no --passalgo=sha512)
+auth --useshadow
+
+# Use text mode install
+text
+
+# System keyboard
+keyboard us
+
+# System language
+lang @@VBOX_INSERT_LOCALE@@
+
+#rhel5 needs:
+@@VBOX_COND_HAS_NO_PRODUCT_KEY@@
+key --skip
+@@VBOX_COND_END@@
+@@VBOX_COND_HAS_PRODUCT_KEY@@
+key @@VBOX_INSERT_PRODUCT_KEY@@
+@@VBOX_COND_END@@
+
+
+# SELinux configuration
+selinux --enforcing
+
+# Installation logging level
+logging --level=info
+
+# System timezone
+timezone@@VBOX_COND_IS_RTC_USING_UTC@@ --utc@@VBOX_COND_END@@ @@VBOX_INSERT_TIME_ZONE_UX@@
+
+# Network information
+network --bootproto=dhcp --device=eth0 --onboot=on --hostname=@@VBOX_INSERT_HOSTNAME_FQDN_SH@@
+
+# System bootloader configuration
+bootloader --location=mbr --append="nomodeset crashkernel=auto rhgb quiet"
+zerombr
+
+# Partition clearing information
+clearpart --all --initlabel
+
+# Disk partitioning information (rhel5: no ext4, so use ext3)
+part / --fstype ext3 --size 6000 --grow --asprimary
+part swap --size 1024
+
+#Initial user
+user --name=@@VBOX_INSERT_USER_LOGIN_SH@@ --password=@@VBOX_INSERT_USER_PASSWORD_SH@@
+
+# Reboot after installation
+# Note! Not sure exctly when the --eject option was added. Need to find out an make it optional.
+reboot --eject
+
+# Packages. We currently ignore missing packages/groups here to keep things simpler.
+%packages --ignoremissing
+ at base
+ at core
+@@VBOX_COND_IS_NOT_MINIMAL_INSTALLATION@@
+ at development
+ at basic-desktop
+ at desktop-debugging
+ at desktop-platform
+ at fonts
+ at general-desktop
+ at graphical-admin-tools
+ at remote-desktop-clients
+ at x11
+@@VBOX_COND_END@@
+
+# Prepare building the additions kernel module, try get what we can from the cdrom as it may be impossible
+# to install anything from the post script:
+kernel-headers
+kernel-devel
+glibc-devel
+glibc-headers
+gcc
+dkms
+make
+bzip2
+perl
+# %end - rhel5 does not like this.
+
+
+# Pre install script for mounting the cdrom, to make sure it cannot be ejcted.
+# See https://bugzilla.redhat.com/show_bug.cgi?id=239002
+%pre
+mkdir -p /tmp/vboxcdrom
+mount -t iso9660 /tmp/cdrom /tmp/vboxcdrom || mount -t iso9660 /dev/hdc /tmp/vboxcdrom || mount -t iso9660 /dev/scd0 /tmp/vboxcdrom || mount -t iso9660 /dev/sdb /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
+
+# Post install happens in a different script.
+# Note! We mount the CDROM explictily here since the location differs between fedora 26 to rhel5
+# and apparently there isn't any way to be certain that anaconda didn't unmount it already.
+# rhel5: There is not /bin/bash, so use /bin/sh
+# rhel5: There is no /dev/cdrom, so try use /dev/hdc and /dev/sdb.
+%post --nochroot --log=/mnt/sysimage/root/ks-post.log
+df -h 1>&2
+cp /tmp/vboxcdrom/vboxpostinstall.sh /mnt/sysimage/root/vboxpostinstall.sh
+chmod a+x /mnt/sysimage/root/vboxpostinstall.sh
+/bin/sh /mnt/sysimage/root/vboxpostinstall.sh --rhel
+umount /tmp/vboxcdrom
+rmdir /tmp/vboxcdrom
+# %end - rhel5 does not like this.
+
diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl
index bd715d9..4a81505 100644
--- a/src/VBox/Main/idl/VirtualBox.xidl
+++ b/src/VBox/Main/idl/VirtualBox.xidl
@@ -1008,7 +1008,7 @@
If set, force an indirect branch prediction barrier on VM exits if the
host CPU supports it. This setting will significantly slow down workloads
causing many VM exits, so it is only recommended for situation where there
- real need to be paranoid.
+ is a real need to be paranoid.
</desc>
</const>
<const name="IBPBOnVMEntry" value="7">
@@ -1016,7 +1016,20 @@
If set, force an indirect branch prediction barrier on VM entry if the
host CPU supports it. This setting will significantly slow down workloads
causing many VM exits, so it is only recommended for situation where there
- real need to be paranoid.
+ is a real need to be paranoid.
+ </desc>
+ </const>
+ <const name="SpecCtrl" value="9">
+ <desc>
+ If set, the speculation control CPUID bits and MSRs, when available on the
+ host, are exposed to the guest. Depending on the host CPU and operating
+ system, this may significantly slow down workloads causing many VM exits.
+ </desc>
+ </const>
+ <const name="SpecCtrlByHost" value="10">
+ <desc>
+ If set, the speculation controls are managed by the host. This is intended
+ for guests which do not set the speculation controls themselves.
</desc>
</const>
</enum>
diff --git a/src/VBox/Main/include/MachineImpl.h b/src/VBox/Main/include/MachineImpl.h
index 4b7a488..e062c2f 100644
--- a/src/VBox/Main/include/MachineImpl.h
+++ b/src/VBox/Main/include/MachineImpl.h
@@ -289,6 +289,8 @@ public:
BOOL mX2APIC;
BOOL mIBPBOnVMExit;
BOOL mIBPBOnVMEntry;
+ BOOL mSpecCtrl;
+ BOOL mSpecCtrlByHost;
ULONG mCPUCount;
BOOL mCPUHotPlugEnabled;
ULONG mCpuExecutionCap;
diff --git a/src/VBox/Main/include/UnattendedImpl.h b/src/VBox/Main/include/UnattendedImpl.h
index 1f94b02..b1ba370 100644
--- a/src/VBox/Main/include/UnattendedImpl.h
+++ b/src/VBox/Main/include/UnattendedImpl.h
@@ -211,6 +211,15 @@ private:
* @param hVfsIso The ISO file system handle.
*/
HRESULT i_innerDetectIsoOS(RTVFS hVfsIso);
+ typedef union DETECTBUFFER
+ {
+ char sz[4096];
+ char ach[4096];
+ uint8_t ab[4096];
+ uint32_t au32[1024];
+ } DETECTBUFFER;
+ HRESULT i_innerDetectIsoOSWindows(RTVFS hVfsIso, DETECTBUFFER *puBuf, VBOXOSTYPE *penmOsType);
+ HRESULT i_innerDetectIsoOSLinux(RTVFS hVfsIso, DETECTBUFFER *puBuf, VBOXOSTYPE *penmOsType);
/**
* Worker for reconfigureVM().
diff --git a/src/VBox/Main/include/UnattendedInstaller.h b/src/VBox/Main/include/UnattendedInstaller.h
index 4d2049f..4659aca 100644
--- a/src/VBox/Main/include/UnattendedInstaller.h
+++ b/src/VBox/Main/include/UnattendedInstaller.h
@@ -92,13 +92,18 @@ public:
* Instantiates the appropriate child class.
*
* @returns Pointer to the new instance, NULL if no appropriate installer.
- * @param enmOsType The guest OS type value.
- * @param strGuestOsType The guest OS type string
- * @param pParent The parent object. Used for setting errors and
- * querying attributes.
+ * @param enmOsType The guest OS type value.
+ * @param strGuestOsType The guest OS type string
+ * @param strDetectedOSVersion The detected guest OS version.
+ * @param strDetectedOSFlavor The detected guest OS flavor.
+ * @param strDetectedOSHints Hints about the detected guest OS.
+ * @param pParent The parent object. Used for setting errors
+ * and querying attributes.
* @throws std::bad_alloc
*/
- static UnattendedInstaller *createInstance(VBOXOSTYPE enmOsType, const Utf8Str &strGuestOsType, Unattended *pParent);
+ static UnattendedInstaller *createInstance(VBOXOSTYPE enmOsType, const Utf8Str &strGuestOsType,
+ const Utf8Str &strDetectedOSVersion, const Utf8Str &strDetectedOSFlavor,
+ const Utf8Str &strDetectedOSHints, Unattended *pParent);
/**
* Initialize the installer.
@@ -481,17 +486,17 @@ public:
/**
- * RedHat 6/7 installer.
+ * RHEL 6 and 7 installer.
*
* This serves as a base for the kickstart based installers.
*/
-class UnattendedRedHat67Installer : public UnattendedLinuxInstaller
+class UnattendedRhel6And7Installer : public UnattendedLinuxInstaller
{
public:
- UnattendedRedHat67Installer(Unattended *pParent,
- const char *pszMainScriptTemplateName = "redhat67_ks.cfg",
- const char *pszPostScriptTemplateName = "redhat_postinstall.sh",
- const char *pszMainScriptFilename = "ks.cfg")
+ UnattendedRhel6And7Installer(Unattended *pParent,
+ const char *pszMainScriptTemplateName = "redhat67_ks.cfg",
+ const char *pszPostScriptTemplateName = "redhat_postinstall.sh",
+ const char *pszMainScriptFilename = "ks.cfg")
: UnattendedLinuxInstaller(pParent, pszMainScriptTemplateName, pszPostScriptTemplateName, pszMainScriptFilename)
{
Assert(!isOriginalIsoNeeded()); Assert(isAuxiliaryIsoNeeded());
@@ -499,7 +504,7 @@ public:
mStrDefaultExtraInstallKernelParameters.assign(" ks=cdrom:/").append(pszMainScriptFilename).append(' ');
mArrStrRemoveInstallKernelParameters.append("rd.live.check"); /* Disables the checkisomd5 step. Required for VISO. */
}
- ~UnattendedRedHat67Installer() {}
+ ~UnattendedRhel6And7Installer() {}
bool isAuxiliaryIsoIsVISO() { return true; }
bool isOriginalIsoNeeded() const { return false; }
@@ -511,26 +516,59 @@ protected:
/**
- * Fedora installer (same as RedHat 6/7, except for the template).
+ * RHEL 5 installer (same as RHEL 6 & 7, except for the kickstart template).
*/
-class UnattendedFedoraInstaller : public UnattendedRedHat67Installer
+class UnattendedRhel5Installer : public UnattendedRhel6And7Installer
+{
+public:
+ UnattendedRhel5Installer(Unattended *pParent) : UnattendedRhel6And7Installer(pParent, "rhel5_ks.cfg") {}
+ ~UnattendedRhel5Installer() {}
+};
+
+
+/**
+ * RHEL 4 installer (same as RHEL 6 & 7, except for the kickstart template).
+ */
+class UnattendedRhel4Installer : public UnattendedRhel6And7Installer
+{
+public:
+ UnattendedRhel4Installer(Unattended *pParent) : UnattendedRhel6And7Installer(pParent, "rhel4_ks.cfg") {}
+ ~UnattendedRhel4Installer() {}
+};
+
+
+/**
+ * RHEL 3 installer (same as RHEL 6 & 7, except for the kickstart template).
+ */
+class UnattendedRhel3Installer : public UnattendedRhel6And7Installer
+{
+public:
+ UnattendedRhel3Installer(Unattended *pParent) : UnattendedRhel6And7Installer(pParent, "rhel3_ks.cfg") {}
+ ~UnattendedRhel3Installer() {}
+};
+
+
+/**
+ * Fedora installer (same as RHEL 6 & 7, except for the template).
+ */
+class UnattendedFedoraInstaller : public UnattendedRhel6And7Installer
{
public:
UnattendedFedoraInstaller(Unattended *pParent)
- : UnattendedRedHat67Installer(pParent, "fedora_ks.cfg")
+ : UnattendedRhel6And7Installer(pParent, "fedora_ks.cfg")
{ Assert(!isOriginalIsoNeeded()); Assert(isAuxiliaryIsoNeeded()); Assert(!isAuxiliaryFloppyNeeded()); Assert(isAuxiliaryIsoIsVISO()); }
~UnattendedFedoraInstaller() {}
};
/**
- * Oracle Linux installer (same as RedHat 6/7, except for the template).
+ * Oracle Linux installer (same as RHEL 6 & 7, except for the template).
*/
-class UnattendedOracleLinuxInstaller : public UnattendedRedHat67Installer
+class UnattendedOracleLinuxInstaller : public UnattendedRhel6And7Installer
{
public:
UnattendedOracleLinuxInstaller(Unattended *pParent)
- : UnattendedRedHat67Installer(pParent, "ol_ks.cfg")
+ : UnattendedRhel6And7Installer(pParent, "ol_ks.cfg")
{ Assert(!isOriginalIsoNeeded()); Assert(isAuxiliaryIsoNeeded()); Assert(!isAuxiliaryFloppyNeeded()); Assert(isAuxiliaryIsoIsVISO()); }
~UnattendedOracleLinuxInstaller() {}
};
diff --git a/src/VBox/Main/src-client/ConsoleImpl2.cpp b/src/VBox/Main/src-client/ConsoleImpl2.cpp
index 07572b2..17fb06c 100644
--- a/src/VBox/Main/src-client/ConsoleImpl2.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl2.cpp
@@ -1013,6 +1013,11 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
}
+ /* Speculation Control. */
+ BOOL fSpecCtrl = FALSE;
+ hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrl, &fSpecCtrl); H();
+ InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
+
/*
* Hardware virtualization extensions.
*/
@@ -1159,6 +1164,10 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
+ BOOL fSpecCtrlByHost = false;
+ hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrlByHost, &fSpecCtrlByHost); H();
+ InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
+
/* Reset overwrite. */
if (i_isResetTurnedIntoPowerOff())
InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
diff --git a/src/VBox/Main/src-client/EBML_MKV.h b/src/VBox/Main/src-client/EBML_MKV.h
index 73d7b2e..0dd50b0 100644
--- a/src/VBox/Main/src-client/EBML_MKV.h
+++ b/src/VBox/Main/src-client/EBML_MKV.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2017 Oracle Corporation
+ * Copyright (C) 2017-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -69,6 +69,7 @@ enum MkvElem
MkvElem_Video = 0xE0,
MkvElem_PixelWidth = 0xB0,
MkvElem_PixelHeight = 0xBA,
+ MkvElem_FrameRate = 0x2383E3,
MkvElem_Audio = 0xE1,
MkvElem_SamplingFrequency = 0xB5,
diff --git a/src/VBox/Main/src-client/VideoRec.cpp b/src/VBox/Main/src-client/VideoRec.cpp
index 61e02ac..bd262e3 100644
--- a/src/VBox/Main/src-client/VideoRec.cpp
+++ b/src/VBox/Main/src-client/VideoRec.cpp
@@ -1108,7 +1108,7 @@ int VideoRecStreamInit(PVIDEORECCONTEXT pCtx, uint32_t uScreen)
break;
}
- LogRel(("VideoRec: Recording screen #%u with %RU32x%RU32 @ %RU32 kbps, %u FPS\n",
+ LogRel(("VideoRec: Recording screen #%u with %RU32x%RU32 @ %RU32 kbps, %RU32 FPS\n",
uScreen, pCfg->Video.uWidth, pCfg->Video.uHeight, pCfg->Video.uRate, pCfg->Video.uFPS));
}
diff --git a/src/VBox/Main/src-client/WebMWriter.cpp b/src/VBox/Main/src-client/WebMWriter.cpp
index 887c5b7..2a3e481 100644
--- a/src/VBox/Main/src-client/WebMWriter.cpp
+++ b/src/VBox/Main/src-client/WebMWriter.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2013-2017 Oracle Corporation
+ * Copyright (C) 2013-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -58,7 +58,7 @@ WebMWriter::WebMWriter(void)
WebMWriter::~WebMWriter(void)
{
- close();
+ Close();
}
/**
@@ -136,11 +136,11 @@ int WebMWriter::Open(const char *a_pszFilename, uint64_t a_fOpen,
*/
int WebMWriter::Close(void)
{
+ LogFlowFuncEnter();
+
if (!isOpen())
return VINF_SUCCESS;
- LogFunc(("\n"));
-
/* Make sure to drain all queues. */
processQueues(&CurSeg.queueBlocks, true /* fForce */);
@@ -202,7 +202,9 @@ int WebMWriter::AddAudioTrack(uint16_t uHz, uint8_t cChannels, uint8_t cBits, ui
if (RT_FAILURE(rc))
return rc;
- const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
+ /* Some players (e.g. Firefox with Nestegg) rely on track numbers starting at 1.
+ * Using a track number 0 will show those files as being corrupted. */
+ const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size() + 1;
subStart(MkvElem_TrackEntry);
@@ -252,15 +254,15 @@ int WebMWriter::AddAudioTrack(uint16_t uHz, uint8_t cChannels, uint8_t cBits, ui
* @returns IPRT status code.
* @param uWidth Width (in pixels) of the video track.
* @param uHeight Height (in pixels) of the video track.
- * @param dbFPS FPS (Frames Per Second) of the video track.
+ * @param uFPS FPS (Frames Per Second) of the video track.
* @param puTrack Track number of the added video track on success. Optional.
*/
-int WebMWriter::AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS, uint8_t *puTrack)
+int WebMWriter::AddVideoTrack(uint16_t uWidth, uint16_t uHeight, uint32_t uFPS, uint8_t *puTrack)
{
#ifdef VBOX_WITH_LIBVPX
- RT_NOREF(dbFPS);
-
- const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size();
+ /* Some players (e.g. Firefox with Nestegg) rely on track numbers starting at 1.
+ * Using a track number 0 will show those files as being corrupted. */
+ const uint8_t uTrack = (uint8_t)CurSeg.mapTracks.size() + 1;
subStart(MkvElem_TrackEntry);
@@ -277,6 +279,9 @@ int WebMWriter::AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS, u
.subStart(MkvElem_Video)
.serializeUnsignedInteger(MkvElem_PixelWidth, uWidth)
.serializeUnsignedInteger(MkvElem_PixelHeight, uHeight)
+ /* Some players rely on the FPS rate for timing calculations.
+ * So make sure to *always* include that. */
+ .serializeFloat (MkvElem_FrameRate, (float)uFPS)
.subEnd(MkvElem_Video);
subEnd(MkvElem_TrackEntry);
@@ -365,7 +370,7 @@ int WebMWriter::writeHeader(void)
/* Save offset of current segment. */
CurSeg.offStart = RTFileTell(getFile());
- writeSegSeekInfo();
+ writeSeekHeader();
/* Save offset of upcoming tracks segment. */
CurSeg.offTracks = RTFileTell(getFile());
@@ -389,9 +394,9 @@ int WebMWriter::writeSimpleBlockEBML(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBl
#ifdef LOG_ENABLED
WebMCluster &Cluster = CurSeg.CurCluster;
- Log3Func(("[T%RU8C%RU64] Off=%RU64, PTS=%RU16, RelToClusterMs=%RU16, %zu bytes\n",
+ Log3Func(("[T%RU8C%RU64] Off=%RU64, AbsPTSMs=%RU64, RelToClusterMs=%RU16, %zu bytes\n",
a_pTrack->uTrack, Cluster.uID, RTFileTell(getFile()),
- a_pBlock->Data.tcPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
+ a_pBlock->Data.tcAbsPTSMs, a_pBlock->Data.tcRelToClusterMs, a_pBlock->Data.cb));
#endif
/*
* Write a "Simple Block".
@@ -399,9 +404,9 @@ int WebMWriter::writeSimpleBlockEBML(WebMTrack *a_pTrack, WebMSimpleBlock *a_pBl
writeClassId(MkvElem_SimpleBlock);
/* Block size. */
writeUnsignedInteger(0x10000000u | ( 1 /* Track number size. */
- + m_cbTimecode /* Timecode size .*/
- + 1 /* Flags size. */
- + a_pBlock->Data.cb /* Actual frame data size. */), 4);
+ + m_cbTimecode /* Timecode size .*/
+ + 1 /* Flags size. */
+ + a_pBlock->Data.cb /* Actual frame data size. */), 4);
/* Track number. */
writeSize(a_pTrack->uTrack);
/* Timecode (relative to cluster opening timecode). */
@@ -429,10 +434,10 @@ int WebMWriter::writeSimpleBlockQueued(WebMTrack *a_pTrack, WebMSimpleBlock *a_p
try
{
- const WebMTimecode tcMap = a_pBlock->Data.tcPTSMs;
+ const WebMTimecodeAbs tcAbsPTS = a_pBlock->Data.tcAbsPTSMs;
/* See if we already have an entry for the specified timecode in our queue. */
- WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcMap);
+ WebMBlockMap::iterator itQueue = CurSeg.queueBlocks.Map.find(tcAbsPTS);
if (itQueue != CurSeg.queueBlocks.Map.end()) /* Use existing queue. */
{
WebMTimecodeBlocks &Blocks = itQueue->second;
@@ -443,7 +448,7 @@ int WebMWriter::writeSimpleBlockQueued(WebMTrack *a_pTrack, WebMSimpleBlock *a_p
WebMTimecodeBlocks Blocks;
Blocks.Enqueue(a_pBlock);
- CurSeg.queueBlocks.Map[tcMap] = Blocks;
+ CurSeg.queueBlocks.Map[tcAbsPTS] = Blocks;
}
processQueues(&CurSeg.queueBlocks, false /* fForce */);
@@ -472,14 +477,13 @@ int WebMWriter::writeSimpleBlockVP8(WebMTrack *a_pTrack, const vpx_codec_enc_cfg
{
RT_NOREF(a_pTrack);
- /* Calculate the PTS of this frame (in ms). */
- WebMTimecode tcPTSMs = a_pPkt->data.frame.pts * 1000
- * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
-
- if ( tcPTSMs
- && tcPTSMs <= a_pTrack->tcLastWrittenMs)
+ /* Calculate the absolute PTS of this frame (in ms). */
+ WebMTimecodeAbs tcAbsPTSMs = a_pPkt->data.frame.pts * 1000
+ * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
+ if ( tcAbsPTSMs
+ && tcAbsPTSMs <= a_pTrack->tcAbsLastWrittenMs)
{
- tcPTSMs = a_pTrack->tcLastWrittenMs + 1;
+ tcAbsPTSMs = a_pTrack->tcAbsLastWrittenMs + 1;
}
const bool fKeyframe = RT_BOOL(a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
@@ -492,7 +496,7 @@ int WebMWriter::writeSimpleBlockVP8(WebMTrack *a_pTrack, const vpx_codec_enc_cfg
return writeSimpleBlockQueued(a_pTrack,
new WebMSimpleBlock(a_pTrack,
- tcPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
+ tcAbsPTSMs, a_pPkt->data.frame.buf, a_pPkt->data.frame.sz, fFlags));
}
#endif /* VBOX_WITH_LIBVPX */
@@ -504,11 +508,11 @@ int WebMWriter::writeSimpleBlockVP8(WebMTrack *a_pTrack, const vpx_codec_enc_cfg
* @param a_pTrack Track ID to write data to.
* @param pvData Pointer to simple data block to write.
* @param cbData Size (in bytes) of simple data block to write.
- * @param uPTSMs PTS of simple data block.
+ * @param tcAbsPTSMs Absolute PTS of simple data block.
*
* @remarks Audio blocks that have same absolute timecode as video blocks SHOULD be written before the video blocks.
*/
-int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs)
+int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs)
{
AssertPtrReturn(a_pTrack, VERR_INVALID_POINTER);
AssertPtrReturn(pvData, VERR_INVALID_POINTER);
@@ -518,8 +522,7 @@ int WebMWriter::writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, si
const uint8_t fFlags = VBOX_WEBM_BLOCK_FLAG_KEY_FRAME;
return writeSimpleBlockQueued(a_pTrack,
- new WebMSimpleBlock(a_pTrack,
- uPTSMs, pvData, cbData, fFlags));
+ new WebMSimpleBlock(a_pTrack, tcAbsPTSMs, pvData, cbData, fFlags));
}
#endif /* VBOX_WITH_LIBOPUS */
@@ -608,13 +611,13 @@ int WebMWriter::WriteBlock(uint8_t uTrack, const void *pvData, size_t cbData)
*/
int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
{
- if (pQueue->tslastProcessedMs == 0)
- pQueue->tslastProcessedMs = RTTimeMilliTS();
+ if (pQueue->tsLastProcessedMs == 0)
+ pQueue->tsLastProcessedMs = RTTimeMilliTS();
if (!fForce)
{
/* Only process when we reached a certain threshold. */
- if (RTTimeMilliTS() - pQueue->tslastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
+ if (RTTimeMilliTS() - pQueue->tsLastProcessedMs < 5000 /* ms */ /** @todo Make this configurable */)
return VINF_SUCCESS;
}
@@ -624,9 +627,8 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
WebMBlockMap::iterator it = pQueue->Map.begin();
while (it != CurSeg.queueBlocks.Map.end())
{
- WebMTimecode mapTC = it->first;
- RT_NOREF(mapTC);
- WebMTimecodeBlocks mapBlocks = it->second;
+ WebMTimecodeAbs mapAbsPTSMs = it->first;
+ WebMTimecodeBlocks mapBlocks = it->second;
/* Whether to start a new cluster or not. */
bool fClusterStart = false;
@@ -636,7 +638,7 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
fClusterStart = true;
/* Did we reach the maximum a cluster can hold? Use a new cluster then. */
- if (mapTC - Cluster.tcStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
+ if (mapAbsPTSMs - Cluster.tcAbsStartMs > VBOX_WEBM_CLUSTER_MAX_LEN_MS)
fClusterStart = true;
/* If the block map indicates that a cluster is needed for this timecode, create one. */
@@ -656,21 +658,31 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
Cluster.fOpen = false;
}
- Cluster.fOpen = true;
- Cluster.uID = CurSeg.cClusters;
- Cluster.tcStartMs = mapTC;
- Cluster.offStart = RTFileTell(getFile());
- Cluster.cBlocks = 0;
+ Cluster.fOpen = true;
+ Cluster.uID = CurSeg.cClusters;
+ Cluster.tcAbsStartMs = mapAbsPTSMs;
+ Cluster.offStart = RTFileTell(getFile());
+ Cluster.cBlocks = 0;
+
+ Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n",
+ Cluster.uID, Cluster.tcAbsStartMs, mapAbsPTSMs, Cluster.offStart));
if (CurSeg.cClusters)
- AssertMsg(Cluster.tcStartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n",
- Cluster.uID, Cluster.offStart));
+ AssertMsg(Cluster.tcAbsStartMs, ("[C%RU64] @ %RU64 starting timecode is 0 which is invalid\n",
+ Cluster.uID, Cluster.offStart));
- Log2Func(("[C%RU64] Start @ %RU64ms (map TC is %RU64) / %RU64 bytes\n",
- Cluster.uID, Cluster.tcStartMs, mapTC, Cluster.offStart));
+ WebMTracks::iterator itTrack = CurSeg.mapTracks.begin();
+ while (itTrack != CurSeg.mapTracks.end())
+ {
+ /* Insert cue points for all tracks if a new cluster has been started. */
+ WebMCuePoint cue(itTrack->second /* pTrack */, Cluster.offStart, Cluster.tcAbsStartMs);
+ CurSeg.lstCues.push_back(cue);
+
+ ++itTrack;
+ }
subStart(MkvElem_Cluster)
- .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcStartMs);
+ .serializeUnsignedInteger(MkvElem_Timecode, Cluster.tcAbsStartMs);
CurSeg.cClusters++;
@@ -687,8 +699,8 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
AssertPtr(pTrack);
/* Calculate the block's relative time code to the current cluster's starting time code. */
- Assert(pBlock->Data.tcPTSMs >= Cluster.tcStartMs);
- pBlock->Data.tcRelToClusterMs = pBlock->Data.tcPTSMs - Cluster.tcStartMs;
+ Assert(pBlock->Data.tcAbsPTSMs >= Cluster.tcAbsStartMs);
+ pBlock->Data.tcRelToClusterMs = pBlock->Data.tcAbsPTSMs - Cluster.tcAbsStartMs;
int rc2 = writeSimpleBlockEBML(pTrack, pBlock);
AssertRC(rc2);
@@ -696,15 +708,17 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
Cluster.cBlocks++;
pTrack->cTotalBlocks++;
- pTrack->tcLastWrittenMs = pBlock->Data.tcPTSMs;
+ pTrack->tcAbsLastWrittenMs = pBlock->Data.tcAbsPTSMs;
- if (CurSeg.tcLastWrittenMs < pTrack->tcLastWrittenMs)
- CurSeg.tcLastWrittenMs = pTrack->tcLastWrittenMs;
+ if (CurSeg.tcAbsLastWrittenMs < pTrack->tcAbsLastWrittenMs)
+ CurSeg.tcAbsLastWrittenMs = pTrack->tcAbsLastWrittenMs;
- /* Save a cue point if this is a keyframe. */
- if (pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME)
+ /* Save a cue point if this is a keyframe (if no new cluster has been started,
+ * as this implies that a cue point already is present. */
+ if ( !fClusterStart
+ && (pBlock->Data.fFlags & VBOX_WEBM_BLOCK_FLAG_KEY_FRAME))
{
- WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, pBlock->Data.tcPTSMs);
+ WebMCuePoint cue(pBlock->pTrack, Cluster.offStart, Cluster.tcAbsStartMs);
CurSeg.lstCues.push_back(cue);
}
@@ -723,7 +737,7 @@ int WebMWriter::processQueues(WebMQueue *pQueue, bool fForce)
Assert(CurSeg.queueBlocks.Map.empty());
- pQueue->tslastProcessedMs = RTTimeMilliTS();
+ pQueue->tsLastProcessedMs = RTTimeMilliTS();
return VINF_SUCCESS;
}
@@ -752,9 +766,8 @@ int WebMWriter::writeFooter(void)
/*
* Write Cues element.
*/
- LogFunc(("Cues @ %RU64\n", RTFileTell(getFile())));
-
CurSeg.offCues = RTFileTell(getFile());
+ LogFunc(("Cues @ %RU64\n", CurSeg.offCues));
subStart(MkvElem_Cues);
@@ -764,17 +777,17 @@ int WebMWriter::writeFooter(void)
/* Sanity. */
AssertPtr(itCuePoint->pTrack);
- LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, TC %RU64)\n",
+ LogFunc(("CuePoint @ %RU64: Track #%RU8 (Cluster @ %RU64, tcAbs=%RU64)\n",
RTFileTell(getFile()), itCuePoint->pTrack->uTrack,
itCuePoint->offCluster, itCuePoint->tcAbs));
subStart(MkvElem_CuePoint)
- .serializeUnsignedInteger(MkvElem_CueTime, itCuePoint->tcAbs)
- .subStart(MkvElem_CueTrackPositions)
- .serializeUnsignedInteger(MkvElem_CueTrack, itCuePoint->pTrack->uTrack)
- .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster, 8)
- .subEnd(MkvElem_CueTrackPositions)
- .subEnd(MkvElem_CuePoint);
+ .serializeUnsignedInteger(MkvElem_CueTime, itCuePoint->tcAbs)
+ .subStart(MkvElem_CueTrackPositions)
+ .serializeUnsignedInteger(MkvElem_CueTrack, itCuePoint->pTrack->uTrack)
+ .serializeUnsignedInteger(MkvElem_CueClusterPosition, itCuePoint->offCluster - CurSeg.offStart, 8)
+ .subEnd(MkvElem_CueTrackPositions)
+ .subEnd(MkvElem_CuePoint);
itCuePoint++;
}
@@ -783,25 +796,25 @@ int WebMWriter::writeFooter(void)
subEnd(MkvElem_Segment);
/*
- * Re-Update SeekHead / Info elements.
+ * Re-Update seek header with final information.
*/
- writeSegSeekInfo();
+ writeSeekHeader();
return RTFileSeek(getFile(), 0, RTFILE_SEEK_END, NULL);
}
/**
- * Writes the segment's seek information and cue points.
+ * Writes the segment's seek header.
*/
-void WebMWriter::writeSegSeekInfo(void)
+void WebMWriter::writeSeekHeader(void)
{
if (CurSeg.offSeekInfo)
RTFileSeek(getFile(), CurSeg.offSeekInfo, RTFILE_SEEK_BEGIN, NULL);
else
CurSeg.offSeekInfo = RTFileTell(getFile());
- LogFunc(("SeekHead @ %RU64\n", CurSeg.offSeekInfo));
+ LogFunc(("Seek Headeder @ %RU64\n", CurSeg.offSeekInfo));
subStart(MkvElem_SeekHead);
@@ -810,7 +823,8 @@ void WebMWriter::writeSegSeekInfo(void)
.serializeUnsignedInteger(MkvElem_SeekPosition, CurSeg.offTracks - CurSeg.offStart, 8)
.subEnd(MkvElem_Seek);
- Assert(CurSeg.offCues - CurSeg.offStart > 0); /* Sanity. */
+ if (CurSeg.offCues)
+ LogFunc(("Updating Cues @ %RU64\n", CurSeg.offCues));
subStart(MkvElem_Seek)
.serializeUnsignedInteger(MkvElem_SeekID, MkvElem_Cues)
@@ -824,7 +838,11 @@ void WebMWriter::writeSegSeekInfo(void)
subEnd(MkvElem_SeekHead);
- //int64_t iFrameTime = (int64_t)1000 * 1 / 25; //m_Framerate.den / m_Framerate.num; /** @todo Fix this! */
+ /*
+ * Write the segment's info element.
+ */
+
+ /* Save offset of the segment's info element. */
CurSeg.offInfo = RTFileTell(getFile());
LogFunc(("Info @ %RU64\n", CurSeg.offInfo));
@@ -839,19 +857,19 @@ void WebMWriter::writeSegSeekInfo(void)
char szApp[64];
RTStrPrintf(szApp, sizeof(szApp), VBOX_PRODUCT " %sr%u", VBOX_VERSION_STRING, RTBldCfgRevision());
- const WebMTimecode tcDuration = CurSeg.tcLastWrittenMs - CurSeg.tcStartMs;
+ const WebMTimecodeAbs tcAbsDurationMs = CurSeg.tcAbsLastWrittenMs - CurSeg.tcAbsStartMs;
if (!CurSeg.lstCues.empty())
{
- LogFunc(("tcDuration=%RU64\n", tcDuration));
- AssertMsg(tcDuration, ("Segment seems to be empty\n"));
+ LogFunc(("tcAbsDurationMs=%RU64\n", tcAbsDurationMs));
+ AssertMsg(tcAbsDurationMs, ("Segment seems to be empty (duration is 0)\n"));
}
subStart(MkvElem_Info)
- .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
- .serializeFloat(MkvElem_Segment_Duration, tcDuration)
- .serializeString(MkvElem_MuxingApp, szMux)
- .serializeString(MkvElem_WritingApp, szApp)
- .subEnd(MkvElem_Info);
+ .serializeUnsignedInteger(MkvElem_TimecodeScale, CurSeg.uTimecodeScaleFactor)
+ .serializeFloat(MkvElem_Segment_Duration, tcAbsDurationMs)
+ .serializeString(MkvElem_MuxingApp, szMux)
+ .serializeString(MkvElem_WritingApp, szApp)
+ .subEnd(MkvElem_Info);
}
diff --git a/src/VBox/Main/src-client/WebMWriter.h b/src/VBox/Main/src-client/WebMWriter.h
index 3bc2c10..a680fce 100644
--- a/src/VBox/Main/src-client/WebMWriter.h
+++ b/src/VBox/Main/src-client/WebMWriter.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2013-2017 Oracle Corporation
+ * Copyright (C) 2013-2018 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -90,8 +90,11 @@ class WebMWriter : public EBMLWriter
public:
- /** Defines a WebM timecode. */
- typedef uint16_t WebMTimecode;
+ /** Defines an absolute WebM timecode (Block + Cluster). */
+ typedef uint64_t WebMTimecodeAbs;
+
+ /** Defines a relative WebM timecode (Block). */
+ typedef uint16_t WebMTimecodeRel;
/** Defines the WebM block flags data type. */
typedef uint8_t WebMBlockFlags;
@@ -139,12 +142,12 @@ public:
struct WebMSimpleBlock
{
WebMSimpleBlock(WebMTrack *a_pTrack,
- WebMTimecode a_tcPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
+ WebMTimecodeAbs a_tcAbsPTSMs, const void *a_pvData, size_t a_cbData, WebMBlockFlags a_fFlags)
: pTrack(a_pTrack)
{
- Data.tcPTSMs = a_tcPTSMs;
- Data.cb = a_cbData;
- Data.fFlags = a_fFlags;
+ Data.tcAbsPTSMs = a_tcAbsPTSMs;
+ Data.cb = a_cbData;
+ Data.fFlags = a_fFlags;
if (Data.cb)
{
@@ -168,8 +171,8 @@ public:
/** Actual simple block data. */
struct
{
- WebMTimecode tcPTSMs;
- WebMTimecode tcRelToClusterMs;
+ WebMTimecodeAbs tcAbsPTSMs;
+ WebMTimecodeRel tcRelToClusterMs;
void *pv;
size_t cb;
WebMBlockFlags fFlags;
@@ -211,7 +214,7 @@ public:
/** A block map containing all currently queued blocks.
* The key specifies a unique timecode, whereas the value
* is a queue of blocks which all correlate to the key (timecode). */
- typedef std::map<WebMTimecode, WebMTimecodeBlocks> WebMBlockMap;
+ typedef std::map<WebMTimecodeAbs, WebMTimecodeBlocks> WebMBlockMap;
/**
* Structure for defining a WebM (encoding) queue.
@@ -219,15 +222,15 @@ public:
struct WebMQueue
{
WebMQueue(void)
- : tcLastBlockWrittenMs(0)
- , tslastProcessedMs(0) { }
+ : tcAbsLastBlockWrittenMs(0)
+ , tsLastProcessedMs(0) { }
/** Blocks as FIFO (queue). */
- WebMBlockMap Map;
- /** Timecode (in ms) of last written block to queue. */
- WebMTimecode tcLastBlockWrittenMs;
+ WebMBlockMap Map;
+ /** Absolute timecode (in ms) of last written block to queue. */
+ WebMTimecodeAbs tcAbsLastBlockWrittenMs;
/** Time stamp (in ms) of when the queue was processed last. */
- uint64_t tslastProcessedMs;
+ uint64_t tsLastProcessedMs;
};
/**
@@ -240,7 +243,7 @@ public:
, uTrack(a_uTrack)
, offUUID(a_offID)
, cTotalBlocks(0)
- , tcLastWrittenMs(0)
+ , tcAbsLastWrittenMs(0)
{
uUUID = RTRandU32();
}
@@ -280,8 +283,8 @@ public:
uint64_t offUUID;
/** Total number of blocks. */
uint64_t cTotalBlocks;
- /** Timecode (in ms) of last write. */
- WebMTimecode tcLastWrittenMs;
+ /** Absoute timecode (in ms) of last write. */
+ WebMTimecodeAbs tcAbsLastWrittenMs;
};
/**
@@ -289,16 +292,16 @@ public:
*/
struct WebMCuePoint
{
- WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecode a_tcAbs)
+ WebMCuePoint(WebMTrack *a_pTrack, uint64_t a_offCluster, WebMTimecodeAbs a_tcAbs)
: pTrack(a_pTrack)
, offCluster(a_offCluster), tcAbs(a_tcAbs) { }
/** Associated track. */
- WebMTrack *pTrack;
+ WebMTrack *pTrack;
/** Offset (in bytes) of the related cluster containing the given position. */
- uint64_t offCluster;
- /** Time code (absolute) of this cue point. */
- WebMTimecode tcAbs;
+ uint64_t offCluster;
+ /** Absolute time code according to the segment time base. */
+ WebMTimecodeAbs tcAbs;
};
/**
@@ -310,20 +313,20 @@ public:
: uID(0)
, offStart(0)
, fOpen(false)
- , tcStartMs(0)
+ , tcAbsStartMs(0)
, cBlocks(0) { }
/** This cluster's ID. */
- uint64_t uID;
+ uint64_t uID;
/** Absolute offset (in bytes) of this cluster.
* Needed for seeking info table. */
- uint64_t offStart;
+ uint64_t offStart;
/** Whether this cluster element is opened currently. */
- bool fOpen;
- /** Timecode (in ms) when this cluster starts. */
- WebMTimecode tcStartMs;
+ bool fOpen;
+ /** Absolute timecode (in ms) when this cluster starts. */
+ WebMTimecodeAbs tcAbsStartMs;
/** Number of (simple) blocks in this cluster. */
- uint64_t cBlocks;
+ uint64_t cBlocks;
};
/**
@@ -334,8 +337,8 @@ public:
struct WebMSegment
{
WebMSegment(void)
- : tcStartMs(0)
- , tcLastWrittenMs(0)
+ : tcAbsStartMs(0)
+ , tcAbsLastWrittenMs(0)
, offStart(0)
, offInfo(0)
, offSeekInfo(0)
@@ -363,10 +366,10 @@ public:
/** The timecode scale factor of this segment. */
uint64_t uTimecodeScaleFactor;
- /** Timecode (in ms) when starting this segment. */
- WebMTimecode tcStartMs;
- /** Timecode (in ms) of last write. */
- WebMTimecode tcLastWrittenMs;
+ /** Absolute timecode (in ms) when starting this segment. */
+ WebMTimecodeAbs tcAbsStartMs;
+ /** Absolute timecode (in ms) of last write. */
+ WebMTimecodeAbs tcAbsLastWrittenMs;
/** Absolute offset (in bytes) of CurSeg. */
uint64_t offStart;
@@ -406,7 +409,7 @@ public:
/** Whether we're currently in the tracks section. */
bool m_fInTracksSection;
- /** Size of timecodes in bytes. */
+ /** Size of timecodes (in bytes). */
size_t m_cbTimecode;
/** Maximum value a timecode can have. */
uint32_t m_uTimecodeMax;
@@ -455,7 +458,7 @@ public:
int AddAudioTrack(uint16_t uHz, uint8_t cChannels, uint8_t cBits, uint8_t *puTrack);
- int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, double dbFPS, uint8_t *puTrack);
+ int AddVideoTrack(uint16_t uWidth, uint16_t uHeight, uint32_t uFPS, uint8_t *puTrack);
int WriteBlock(uint8_t uTrack, const void *pvData, size_t cbData);
@@ -473,7 +476,7 @@ protected:
int writeHeader(void);
- void writeSegSeekInfo(void);
+ void writeSeekHeader(void);
int writeFooter(void);
@@ -486,7 +489,7 @@ protected:
#endif
#ifdef VBOX_WITH_LIBOPUS
- int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecode uPTSMs);
+ int writeSimpleBlockOpus(WebMTrack *a_pTrack, const void *pvData, size_t cbData, WebMTimecodeAbs tcAbsPTSMs);
#endif
int processQueues(WebMQueue *pQueue, bool fForce);
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index 70cc1ca..d05525a 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -196,6 +196,8 @@ Machine::HWData::HWData()
mX2APIC = false;
mIBPBOnVMExit = false;
mIBPBOnVMEntry = false;
+ mSpecCtrl = false;
+ mSpecCtrlByHost = false;
mHPETEnabled = false;
mCpuExecutionCap = 100; /* Maximum CPU execution cap by default. */
mCpuIdPortabilityLevel = 0;
@@ -2264,6 +2266,14 @@ HRESULT Machine::getCPUProperty(CPUPropertyType_T aProperty, BOOL *aValue)
*aValue = mHWData->mIBPBOnVMEntry;
break;
+ case CPUPropertyType_SpecCtrl:
+ *aValue = mHWData->mSpecCtrl;
+ break;
+
+ case CPUPropertyType_SpecCtrlByHost:
+ *aValue = mHWData->mSpecCtrlByHost;
+ break;
+
default:
return E_INVALIDARG;
}
@@ -2325,6 +2335,18 @@ HRESULT Machine::setCPUProperty(CPUPropertyType_T aProperty, BOOL aValue)
mHWData->mIBPBOnVMEntry = !!aValue;
break;
+ case CPUPropertyType_SpecCtrl:
+ i_setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mSpecCtrl = !!aValue;
+ break;
+
+ case CPUPropertyType_SpecCtrlByHost:
+ i_setModified(IsModified_MachineData);
+ mHWData.backup();
+ mHWData->mSpecCtrlByHost = !!aValue;
+ break;
+
default:
return E_INVALIDARG;
}
@@ -8922,6 +8944,8 @@ HRESULT Machine::i_loadHardware(const Guid *puuidRegistry,
mHWData->mX2APIC = data.fX2APIC;
mHWData->mIBPBOnVMExit = data.fIBPBOnVMExit;
mHWData->mIBPBOnVMEntry = data.fIBPBOnVMEntry;
+ mHWData->mSpecCtrl = data.fSpecCtrl;
+ mHWData->mSpecCtrlByHost = data.fSpecCtrlByHost;
mHWData->mCPUCount = data.cCPUs;
mHWData->mCPUHotPlugEnabled = data.fCpuHotPlug;
mHWData->mCpuExecutionCap = data.ulCpuExecutionCap;
@@ -10247,6 +10271,8 @@ HRESULT Machine::i_saveHardware(settings::Hardware &data, settings::Debugging *p
data.fX2APIC = !!mHWData->mX2APIC;
data.fIBPBOnVMExit = !!mHWData->mIBPBOnVMExit;
data.fIBPBOnVMEntry = !!mHWData->mIBPBOnVMEntry;
+ data.fSpecCtrl = !!mHWData->mSpecCtrl;
+ data.fSpecCtrlByHost = !!mHWData->mSpecCtrlByHost;
data.cCPUs = mHWData->mCPUCount;
data.fCpuHotPlug = !!mHWData->mCPUHotPlugEnabled;
data.ulCpuExecutionCap = mHWData->mCpuExecutionCap;
diff --git a/src/VBox/Main/src-server/UnattendedImpl.cpp b/src/VBox/Main/src-server/UnattendedImpl.cpp
index 1156f30..59e699c 100644
--- a/src/VBox/Main/src-server/UnattendedImpl.cpp
+++ b/src/VBox/Main/src-server/UnattendedImpl.cpp
@@ -348,19 +348,39 @@ HRESULT Unattended::detectIsoOS()
HRESULT Unattended::i_innerDetectIsoOS(RTVFS hVfsIso)
{
- union
+ DETECTBUFFER uBuf;
+ VBOXOSTYPE enmOsType = VBOXOSTYPE_Unknown;
+ HRESULT hrc = i_innerDetectIsoOSWindows(hVfsIso, &uBuf, &enmOsType);
+ if (hrc == S_FALSE && enmOsType == VBOXOSTYPE_Unknown)
+ hrc = i_innerDetectIsoOSLinux(hVfsIso, &uBuf, &enmOsType);
+ if (enmOsType != VBOXOSTYPE_Unknown)
{
- char sz[4096];
- } uBuf;
+ try { mStrDetectedOSTypeId = Global::OSTypeId(enmOsType); }
+ catch (std::bad_alloc) { hrc = E_OUTOFMEMORY; }
+ }
+ return hrc;
+}
+/**
+ * Detect Windows ISOs.
+ *
+ * @returns COM status code.
+ * @retval S_OK if detected
+ * @retval S_FALSE if not fully detected.
+ *
+ * @param hVfsIso The ISO file system.
+ * @param pBuf Read buffer.
+ * @param penmOsType Where to return the OS type. This is initialized to
+ * VBOXOSTYPE_Unknown.
+ */
+HRESULT Unattended::i_innerDetectIsoOSWindows(RTVFS hVfsIso, DETECTBUFFER *pBuf, VBOXOSTYPE *penmOsType)
+{
/** @todo The 'sources/' path can differ. */
// globalinstallorder.xml - vista beta2
// sources/idwbinfo.txt - ditto.
// sources/lang.ini - ditto.
- VBOXOSTYPE enmOsType = VBOXOSTYPE_Unknown;
-
/*
* Try look for the 'sources/idwbinfo.txt' file containing windows build info.
* This file appeared with Vista beta 2 from what we can tell. Before windows 10
@@ -370,58 +390,52 @@ HRESULT Unattended::i_innerDetectIsoOS(RTVFS hVfsIso)
int vrc = RTVfsFileOpen(hVfsIso, "sources/idwbinfo.txt", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
if (RT_SUCCESS(vrc))
{
- enmOsType = VBOXOSTYPE_WinNT_x64;
+ *penmOsType = VBOXOSTYPE_WinNT_x64;
RTINIFILE hIniFile;
vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
RTVfsFileRelease(hVfsFile);
if (RT_SUCCESS(vrc))
{
- vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildArch", uBuf.sz, sizeof(uBuf), NULL);
+ vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildArch", pBuf->sz, sizeof(*pBuf), NULL);
if (RT_SUCCESS(vrc))
{
- LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildArch=%s\n", uBuf.sz));
- if ( RTStrNICmp(uBuf.sz, RT_STR_TUPLE("amd64")) == 0
- || RTStrNICmp(uBuf.sz, RT_STR_TUPLE("x64")) == 0 /* just in case */ )
- enmOsType = VBOXOSTYPE_WinNT_x64;
- else if (RTStrNICmp(uBuf.sz, RT_STR_TUPLE("x86")) == 0)
- enmOsType = VBOXOSTYPE_WinNT;
+ LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildArch=%s\n", pBuf->sz));
+ if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("amd64")) == 0
+ || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("x64")) == 0 /* just in case */ )
+ *penmOsType = VBOXOSTYPE_WinNT_x64;
+ else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("x86")) == 0)
+ *penmOsType = VBOXOSTYPE_WinNT;
else
{
- LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildArch=%s\n", uBuf.sz));
- enmOsType = VBOXOSTYPE_WinNT_x64;
+ LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildArch=%s\n", pBuf->sz));
+ *penmOsType = VBOXOSTYPE_WinNT_x64;
}
}
- vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildBranch", uBuf.sz, sizeof(uBuf), NULL);
+ vrc = RTIniFileQueryValue(hIniFile, "BUILDINFO", "BuildBranch", pBuf->sz, sizeof(*pBuf), NULL);
if (RT_SUCCESS(vrc))
{
- LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildBranch=%s\n", uBuf.sz));
- if ( RTStrNICmp(uBuf.sz, RT_STR_TUPLE("vista")) == 0
- || RTStrNICmp(uBuf.sz, RT_STR_TUPLE("winmain_beta")) == 0)
- enmOsType = (VBOXOSTYPE)((enmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_WinVista);
- else if (RTStrNICmp(uBuf.sz, RT_STR_TUPLE("win7")) == 0)
- enmOsType = (VBOXOSTYPE)((enmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win7);
- else if ( RTStrNICmp(uBuf.sz, RT_STR_TUPLE("winblue")) == 0
- || RTStrNICmp(uBuf.sz, RT_STR_TUPLE("winmain_blue")) == 0
- || RTStrNICmp(uBuf.sz, RT_STR_TUPLE("win81")) == 0 /* not seen, but just in case its out there */ )
- enmOsType = (VBOXOSTYPE)((enmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win81);
- else if ( RTStrNICmp(uBuf.sz, RT_STR_TUPLE("win8")) == 0
- || RTStrNICmp(uBuf.sz, RT_STR_TUPLE("winmain_win8")) == 0 )
- enmOsType = (VBOXOSTYPE)((enmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win8);
+ LogRelFlow(("Unattended: sources/idwbinfo.txt: BuildBranch=%s\n", pBuf->sz));
+ if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("vista")) == 0
+ || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_beta")) == 0)
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_WinVista);
+ else if (RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win7")) == 0)
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win7);
+ else if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winblue")) == 0
+ || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_blue")) == 0
+ || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win81")) == 0 /* not seen, but just in case its out there */ )
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win81);
+ else if ( RTStrNICmp(pBuf->sz, RT_STR_TUPLE("win8")) == 0
+ || RTStrNICmp(pBuf->sz, RT_STR_TUPLE("winmain_win8")) == 0 )
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Win8);
else
- LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildBranch=%s\n", uBuf.sz));
+ LogRel(("Unattended: sources/idwbinfo.txt: Unknown: BuildBranch=%s\n", pBuf->sz));
}
RTIniFileRelease(hIniFile);
}
}
- if ( enmOsType != VBOXOSTYPE_Unknown
- && enmOsType != VBOXOSTYPE_Unknown_x64)
- {
- mStrDetectedOSTypeId = Global::OSTypeId(enmOsType);
- }
-
/*
* Look for sources/lang.ini and try parse it to get the languages out of it.
*/
@@ -440,9 +454,9 @@ HRESULT Unattended::i_innerDetectIsoOS(RTVFS hVfsIso)
uint32_t idxPair;
for (idxPair = 0; idxPair < 256; idxPair++)
{
- size_t cbHalf = sizeof(uBuf) / 2;
- char *pszKey = uBuf.sz;
- char *pszValue = &uBuf.sz[cbHalf];
+ size_t cbHalf = sizeof(*pBuf) / 2;
+ char *pszKey = pBuf->sz;
+ char *pszValue = &pBuf->sz[cbHalf];
vrc = RTIniFileQueryPair(hIniFile, "Available UI Languages", idxPair,
pszKey, cbHalf, NULL, pszValue, cbHalf, NULL);
if (RT_SUCCESS(vrc))
@@ -468,6 +482,311 @@ HRESULT Unattended::i_innerDetectIsoOS(RTVFS hVfsIso)
}
}
+ /** @todo look at the install.wim file too, extracting the XML (easy) and
+ * figure out the available image numbers and such. The format is
+ * documented. */
+
+ return S_FALSE;
+}
+
+/**
+ * Detects linux architecture.
+ *
+ * @returns true if detected, false if not.
+ * @param pszArch The architecture string.
+ * @param penmOsType Where to return the arch and type on success.
+ * @param enmBaseOsType The base (x86) OS type to return.
+ */
+static bool detectLinuxArch(const char *pszArch, VBOXOSTYPE *penmOsType, VBOXOSTYPE enmBaseOsType)
+{
+ if ( RTStrNICmp(pszArch, RT_STR_TUPLE("amd64")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("x86_64")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("x86-64")) == 0 /* just in case */
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("x64")) == 0 /* ditto */ )
+ {
+ *penmOsType = (VBOXOSTYPE)(enmBaseOsType | VBOXOSTYPE_x64);
+ return true;
+ }
+
+ if ( RTStrNICmp(pszArch, RT_STR_TUPLE("x86")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i386")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i486")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i586")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i686")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i786")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i886")) == 0
+ || RTStrNICmp(pszArch, RT_STR_TUPLE("i986")) == 0)
+ {
+ *penmOsType = enmBaseOsType;
+ return true;
+ }
+
+ /** @todo check for 'noarch' since source CDs have been seen to use that. */
+ return false;
+}
+
+static bool detectLinuxDistroName(const char *pszOsAndVersion, VBOXOSTYPE *penmOsType, const char **ppszNext)
+{
+ bool fRet = true;
+
+ if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Red")) == 0
+ && !RT_C_IS_ALNUM(pszOsAndVersion[3]))
+
+ {
+ pszOsAndVersion = RTStrStripL(pszOsAndVersion + 3);
+ if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Hat")) == 0
+ && !RT_C_IS_ALNUM(pszOsAndVersion[3]))
+ {
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_RedHat);
+ pszOsAndVersion = RTStrStripL(pszOsAndVersion + 3);
+ }
+ else
+ fRet = false;
+ }
+ else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Oracle")) == 0
+ && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
+ {
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_Oracle);
+ pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
+ }
+ else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("CentOS")) == 0
+ && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
+ {
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_RedHat);
+ pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
+ }
+ else if ( RTStrNICmp(pszOsAndVersion, RT_STR_TUPLE("Fedora")) == 0
+ && !RT_C_IS_ALNUM(pszOsAndVersion[6]))
+ {
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_FedoraCore);
+ pszOsAndVersion = RTStrStripL(pszOsAndVersion + 6);
+ }
+ else
+ fRet = false;
+
+ /*
+ * Skip forward till we get a number.
+ */
+ if (ppszNext)
+ {
+ *ppszNext = pszOsAndVersion;
+ char ch;
+ for (const char *pszVersion = pszOsAndVersion; (ch = *pszVersion) != '\0'; pszVersion++)
+ if (RT_C_IS_DIGIT(ch))
+ {
+ *ppszNext = pszVersion;
+ break;
+ }
+ }
+ return fRet;
+}
+
+
+/**
+ * Detect Linux distro ISOs.
+ *
+ * @returns COM status code.
+ * @retval S_OK if detected
+ * @retval S_FALSE if not fully detected.
+ *
+ * @param hVfsIso The ISO file system.
+ * @param pBuf Read buffer.
+ * @param penmOsType Where to return the OS type. This is initialized to
+ * VBOXOSTYPE_Unknown.
+ */
+HRESULT Unattended::i_innerDetectIsoOSLinux(RTVFS hVfsIso, DETECTBUFFER *pBuf, VBOXOSTYPE *penmOsType)
+{
+ /*
+ * Redhat and derivatives may have a .treeinfo (ini-file style) with useful info
+ * or at least a barebone .discinfo file.
+ */
+
+ /*
+ * Start with .treeinfo: https://release-engineering.github.io/productmd/treeinfo-1.0.html
+ */
+ RTVFSFILE hVfsFile;
+ int vrc = RTVfsFileOpen(hVfsIso, ".treeinfo", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
+ if (RT_SUCCESS(vrc))
+ {
+ RTINIFILE hIniFile;
+ vrc = RTIniFileCreateFromVfsFile(&hIniFile, hVfsFile, RTINIFILE_F_READONLY);
+ RTVfsFileRelease(hVfsFile);
+ if (RT_SUCCESS(vrc))
+ {
+ /* Try figure the architecture first (like with windows). */
+ vrc = RTIniFileQueryValue(hIniFile, "tree", "arch", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_FAILURE(vrc) || !pBuf->sz[0])
+ vrc = RTIniFileQueryValue(hIniFile, "general", "arch", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_SUCCESS(vrc))
+ {
+ LogRelFlow(("Unattended: .treeinfo: arch=%s\n", pBuf->sz));
+ if (!detectLinuxArch(pBuf->sz, penmOsType, VBOXOSTYPE_RedHat))
+ LogRel(("Unattended: .treeinfo: Unknown: arch='%s'\n", pBuf->sz));
+ }
+ else
+ LogRel(("Unattended: .treeinfo: No 'arch' property.\n"));
+
+ /* Try figure the release name, it doesn't have to be redhat. */
+ vrc = RTIniFileQueryValue(hIniFile, "release", "name", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_FAILURE(vrc) || !pBuf->sz[0])
+ vrc = RTIniFileQueryValue(hIniFile, "product", "name", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_FAILURE(vrc) || !pBuf->sz[0])
+ vrc = RTIniFileQueryValue(hIniFile, "general", "family", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_SUCCESS(vrc))
+ {
+ LogRelFlow(("Unattended: .treeinfo: name/family=%s\n", pBuf->sz));
+ if (!detectLinuxDistroName(pBuf->sz, penmOsType, NULL))
+ {
+ LogRel(("Unattended: .treeinfo: Unknown: name/family='%s', assuming Red Hat\n", pBuf->sz));
+ *penmOsType = (VBOXOSTYPE)((*penmOsType & VBOXOSTYPE_x64) | VBOXOSTYPE_RedHat);
+ }
+ }
+
+ /* Try figure the version. */
+ vrc = RTIniFileQueryValue(hIniFile, "release", "version", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_FAILURE(vrc) || !pBuf->sz[0])
+ vrc = RTIniFileQueryValue(hIniFile, "product", "version", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_FAILURE(vrc) || !pBuf->sz[0])
+ vrc = RTIniFileQueryValue(hIniFile, "general", "version", pBuf->sz, sizeof(*pBuf), NULL);
+ if (RT_SUCCESS(vrc))
+ {
+ LogRelFlow(("Unattended: .treeinfo: version=%s\n", pBuf->sz));
+ try { mStrDetectedOSVersion = RTStrStrip(pBuf->sz); }
+ catch (std::bad_alloc) { return E_OUTOFMEMORY; }
+ }
+
+ RTIniFileRelease(hIniFile);
+ }
+
+ if (*penmOsType != VBOXOSTYPE_Unknown)
+ return S_FALSE;
+ }
+
+ /*
+ * Try .discinfo next: https://release-engineering.github.io/productmd/discinfo-1.0.html
+ * We will probably need additional info here...
+ */
+ vrc = RTVfsFileOpen(hVfsIso, ".discinfo", RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, &hVfsFile);
+ if (RT_SUCCESS(vrc))
+ {
+ RT_ZERO(*pBuf);
+ size_t cchIgn;
+ RTVfsFileRead(hVfsFile, pBuf->sz, sizeof(*pBuf) - 1, &cchIgn);
+ pBuf->sz[sizeof(*pBuf) - 1] = '\0';
+ RTVfsFileRelease(hVfsFile);
+
+ /* Parse and strip the first 5 lines. */
+ const char *apszLines[5];
+ char *psz = pBuf->sz;
+ for (unsigned i = 0; i < RT_ELEMENTS(apszLines); i++)
+ {
+ apszLines[i] = psz;
+ if (*psz)
+ {
+ char *pszEol = (char *)strchr(psz, '\n');
+ if (!pszEol)
+ psz = strchr(psz, '\0');
+ else
+ {
+ *pszEol = '\0';
+ apszLines[i] = RTStrStrip(psz);
+ psz = pszEol + 1;
+ }
+ }
+ }
+
+ /* Do we recognize the architecture? */
+ LogRelFlow(("Unattended: .discinfo: arch=%s\n", apszLines[2]));
+ if (!detectLinuxArch(apszLines[2], penmOsType, VBOXOSTYPE_RedHat))
+ LogRel(("Unattended: .discinfo: Unknown: arch='%s'\n", apszLines[2]));
+
+ /* Do we recognize the release string? */
+ LogRelFlow(("Unattended: .discinfo: product+version=%s\n", apszLines[1]));
+ const char *pszVersion = NULL;
+ if (!detectLinuxDistroName(apszLines[1], penmOsType, &pszVersion))
+ LogRel(("Unattended: .discinfo: Unknown: release='%s'\n", apszLines[1]));
+
+ if (*pszVersion)
+ {
+ LogRelFlow(("Unattended: .discinfo: version=%s\n", pszVersion));
+ try { mStrDetectedOSVersion = RTStrStripL(pszVersion); }
+ catch (std::bad_alloc) { return E_OUTOFMEMORY; }
+
+ /* CentOS likes to call their release 'Final' without mentioning the actual version
+ number (e.g. CentOS-4.7-x86_64-binDVD.iso), so we need to go look elsewhere.
+ This is only important for centos 4.x and 3.x releases. */
+ if (RTStrNICmp(pszVersion, RT_STR_TUPLE("Final")) == 0)
+ {
+ static const char * const s_apszDirs[] = { "CentOS/RPMS/", "RedHat/RPMS", "Server", "Workstation" };
+ for (unsigned iDir = 0; iDir < RT_ELEMENTS(s_apszDirs); iDir++)
+ {
+ RTVFSDIR hVfsDir;
+ vrc = RTVfsDirOpen(hVfsIso, s_apszDirs[iDir], 0, &hVfsDir);
+ if (RT_FAILURE(vrc))
+ continue;
+ char szRpmDb[128];
+ char szReleaseRpm[128];
+ szRpmDb[0] = '\0';
+ szReleaseRpm[0] = '\0';
+ for (;;)
+ {
+ RTDIRENTRYEX DirEntry;
+ size_t cbDirEntry = sizeof(DirEntry);
+ vrc = RTVfsDirReadEx(hVfsDir, &DirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING);
+ if (RT_FAILURE(vrc))
+ break;
+
+ /* redhat-release-4WS-2.4.i386.rpm
+ centos-release-4-7.x86_64.rpm, centos-release-4-4.3.i386.rpm
+ centos-release-5-3.el5.centos.1.x86_64.rpm */
+ if ( (psz = strstr(DirEntry.szName, "-release-")) != NULL
+ || (psz = strstr(DirEntry.szName, "-RELEASE-")) != NULL)
+ {
+ psz += 9;
+ if (RT_C_IS_DIGIT(*psz))
+ RTStrCopy(szReleaseRpm, sizeof(szReleaseRpm), psz);
+ }
+ /* rpmdb-redhat-4WS-2.4.i386.rpm,
+ rpmdb-CentOS-4.5-0.20070506.i386.rpm,
+ rpmdb-redhat-3.9-0.20070703.i386.rpm. */
+ else if ( ( RTStrStartsWith(DirEntry.szName, "rpmdb-")
+ || RTStrStartsWith(DirEntry.szName, "RPMDB-"))
+ && RT_C_IS_DIGIT(DirEntry.szName[6]) )
+ RTStrCopy(szRpmDb, sizeof(szRpmDb), &DirEntry.szName[6]);
+ }
+ RTVfsDirRelease(hVfsDir);
+
+ /* Did we find anything relvant? */
+ psz = szRpmDb;
+ if (!RT_C_IS_DIGIT(*psz))
+ psz = szReleaseRpm;
+ if (RT_C_IS_DIGIT(*psz))
+ {
+ /* Convert '-' to '.' and strip stuff which doesn't look like a version string. */
+ char *pszCur = psz + 1;
+ for (char ch = *pszCur; ch != '\0'; ch = *++pszCur)
+ if (ch == '-')
+ *pszCur = '.';
+ else if (ch != '.' && !RT_C_IS_DIGIT(ch))
+ {
+ *pszCur = '\0';
+ break;
+ }
+ while (&pszCur[-1] != psz && pszCur[-1] == '.')
+ *--pszCur = '\0';
+
+ /* Set it and stop looking. */
+ try { mStrDetectedOSVersion = psz; }
+ catch (std::bad_alloc) { return E_OUTOFMEMORY; }
+ break;
+ }
+ }
+ }
+ }
+
+ if (*penmOsType != VBOXOSTYPE_Unknown)
+ return S_FALSE;
+ }
return S_FALSE;
}
@@ -657,7 +976,8 @@ HRESULT Unattended::prepare()
uint32_t const idxOSType = Global::getOSTypeIndexFromId(mStrGuestOsTypeId.c_str());
meGuestOsType = idxOSType < Global::cOSTypes ? Global::sOSTypes[idxOSType].osType : VBOXOSTYPE_Unknown;
- mpInstaller = UnattendedInstaller::createInstance(meGuestOsType, mStrGuestOsTypeId, this);
+ mpInstaller = UnattendedInstaller::createInstance(meGuestOsType, mStrGuestOsTypeId, mStrDetectedOSVersion,
+ mStrDetectedOSFlavor, mStrDetectedOSHints, this);
if (mpInstaller != NULL)
{
hrc = mpInstaller->initInstaller();
diff --git a/src/VBox/Main/src-server/UnattendedInstaller.cpp b/src/VBox/Main/src-server/UnattendedInstaller.cpp
index 6b0b3c4..32b35f7 100644
--- a/src/VBox/Main/src-server/UnattendedInstaller.cpp
+++ b/src/VBox/Main/src-server/UnattendedInstaller.cpp
@@ -49,7 +49,11 @@
using namespace std;
-/* static */ UnattendedInstaller *UnattendedInstaller::createInstance(VBOXOSTYPE enmOsType, const Utf8Str &strGuestOsType,
+/* static */ UnattendedInstaller *UnattendedInstaller::createInstance(VBOXOSTYPE enmOsType,
+ const Utf8Str &strGuestOsType,
+ const Utf8Str &strDetectedOSVersion,
+ const Utf8Str &strDetectedOSFlavor,
+ const Utf8Str &strDetectedOSHints,
Unattended *pParent)
{
UnattendedInstaller *pUinstaller = NULL;
@@ -68,7 +72,19 @@ using namespace std;
else if (enmOsType >= VBOXOSTYPE_Ubuntu && enmOsType <= VBOXOSTYPE_Ubuntu_x64)
pUinstaller = new UnattendedUbuntuInstaller(pParent);
else if (enmOsType >= VBOXOSTYPE_RedHat && enmOsType <= VBOXOSTYPE_RedHat_x64)
- pUinstaller = new UnattendedRedHat67Installer(pParent);
+ {
+ if ( strDetectedOSVersion.isEmpty()
+ || RTStrVersionCompare(strDetectedOSVersion.c_str(), "6") >= 0)
+ pUinstaller = new UnattendedRhel6And7Installer(pParent);
+ else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "5") >= 0)
+ pUinstaller = new UnattendedRhel5Installer(pParent);
+ else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "4") >= 0)
+ pUinstaller = new UnattendedRhel4Installer(pParent);
+ else if (RTStrVersionCompare(strDetectedOSVersion.c_str(), "3") >= 0)
+ pUinstaller = new UnattendedRhel3Installer(pParent);
+ else
+ pUinstaller = new UnattendedRhel6And7Installer(pParent);
+ }
else if (enmOsType >= VBOXOSTYPE_FedoraCore && enmOsType <= VBOXOSTYPE_FedoraCore_x64)
pUinstaller = new UnattendedFedoraInstaller(pParent);
else if (enmOsType >= VBOXOSTYPE_Oracle && enmOsType <= VBOXOSTYPE_Oracle_x64)
@@ -78,6 +94,8 @@ using namespace std;
pUinstaller = new UnattendedSuseInstaller(new UnattendedSUSEXMLScript(pParent), pParent);
#endif
}
+ RT_NOREF_PV(strDetectedOSFlavor);
+ RT_NOREF_PV(strDetectedOSHints);
return pUinstaller;
}
@@ -1036,12 +1054,12 @@ HRESULT UnattendedDebianInstaller::editDebianTxtCfg(GeneralTextScript *pEditor)
/*
*
*
-* Implementation UnattendedRedHat67Installer functions
+* Implementation UnattendedRhel6And7Installer functions
*
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
-HRESULT UnattendedRedHat67Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
- RTVFS hVfsOrgIso, bool fOverwrite)
+HRESULT UnattendedRhel6And7Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
+ RTVFS hVfsOrgIso, bool fOverwrite)
{
Utf8Str strIsoLinuxCfg;
try
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index f7d3ce4..a5ecbe2 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -2779,6 +2779,8 @@ Hardware::Hardware() :
fX2APIC(false),
fIBPBOnVMExit(false),
fIBPBOnVMEntry(false),
+ fSpecCtrl(false),
+ fSpecCtrlByHost(false),
enmLongMode(HC_ARCH_BITS == 64 ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled),
cCPUs(1),
fCpuHotPlug(false),
@@ -2934,6 +2936,8 @@ bool Hardware::operator==(const Hardware& h) const
&& fX2APIC == h.fX2APIC
&& fIBPBOnVMExit == h.fIBPBOnVMExit
&& fIBPBOnVMEntry == h.fIBPBOnVMEntry
+ && fSpecCtrl == h.fSpecCtrl
+ && fSpecCtrlByHost == h.fSpecCtrlByHost
&& cCPUs == h.cCPUs
&& fCpuHotPlug == h.fCpuHotPlug
&& ulCpuExecutionCap == h.ulCpuExecutionCap
@@ -3942,6 +3946,12 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
pelmCPUChild->getAttributeValue("vmexit", hw.fIBPBOnVMExit);
pelmCPUChild->getAttributeValue("vmentry", hw.fIBPBOnVMEntry);
}
+ pelmCPUChild = pelmHwChild->findChildElement("SpecCtrl");
+ if (pelmCPUChild)
+ pelmCPUChild->getAttributeValue("enabled", hw.fSpecCtrl);
+ pelmCPUChild = pelmHwChild->findChildElement("SpecCtrlByHost");
+ if (pelmCPUChild)
+ pelmCPUChild->getAttributeValue("enabled", hw.fSpecCtrlByHost);
if ((pelmCPUChild = pelmHwChild->findChildElement("CpuIdTree")))
readCpuIdTree(*pelmCPUChild, hw.llCpuIdLeafs);
@@ -5277,6 +5287,10 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
pelmChild->setAttribute("vmentry", hw.fIBPBOnVMEntry);
}
}
+ if (m->sv >= SettingsVersion_v1_16 && hw.fSpecCtrl)
+ pelmCPU->createChild("SpecCtrl")->setAttribute("enabled", hw.fSpecCtrl);
+ if (m->sv >= SettingsVersion_v1_16 && hw.fSpecCtrlByHost)
+ pelmCPU->createChild("SpecCtrlByHost")->setAttribute("enabled", hw.fSpecCtrlByHost);
if (m->sv >= SettingsVersion_v1_14 && hw.enmLongMode != Hardware::LongMode_Legacy)
{
// LongMode has too crazy default handling, must always save this setting.
@@ -6949,7 +6963,9 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
|| !hardwareMachine.fAPIC
|| hardwareMachine.fX2APIC
|| hardwareMachine.fIBPBOnVMExit
- || hardwareMachine.fIBPBOnVMEntry)
+ || hardwareMachine.fIBPBOnVMEntry
+ || hardwareMachine.fSpecCtrl
+ || hardwareMachine.fSpecCtrlByHost)
{
m->sv = SettingsVersion_v1_16;
return;
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk
index ba4b670..0e173a2 100644
--- a/src/VBox/Runtime/Makefile.kmk
+++ b/src/VBox/Runtime/Makefile.kmk
@@ -2262,6 +2262,7 @@ RuntimeR0Drv_SOURCES.linux = \
r0drv/powernotification-r0drv.c
RuntimeR0Drv_SOURCES.win = \
+ common/asm/ASMCpuIdExSlow.asm \
common/ldr/ldr.cpp \
common/ldr/ldrEx.cpp \
common/ldr/ldrPE.cpp \
diff --git a/src/VBox/Runtime/common/asn1/asn1-ut-time.cpp b/src/VBox/Runtime/common/asn1/asn1-ut-time.cpp
index 8c5aaa5..6fd0995 100644
--- a/src/VBox/Runtime/common/asn1/asn1-ut-time.cpp
+++ b/src/VBox/Runtime/common/asn1/asn1-ut-time.cpp
@@ -80,10 +80,8 @@ RTDECL(int) RTAsn1Time_CompareWithTimeSpec(PCRTASN1TIME pLeft, PCRTTIMESPEC pTsR
int iDiff = RTAsn1Time_IsPresent(pLeft) ? 0 : -1;
if (!iDiff)
{
- RTTIMESPEC TsLeft;
- AssertReturn(RTTimeImplode(&TsLeft, &pLeft->Time), -1);
-
- iDiff = RTTimeSpecCompare(&TsLeft, pTsRight);
+ RTTIME RightTime;
+ iDiff = RTTimeCompare(&pLeft->Time, RTTimeExplode(&RightTime, pTsRight));
}
return iDiff;
@@ -171,15 +169,7 @@ RTDECL(int) RTAsn1Time_Compare(PCRTASN1TIME pLeft, PCRTASN1TIME pRight)
if (RTAsn1Time_IsPresent(pLeft))
{
if (RTAsn1Time_IsPresent(pRight))
- {
- RTTIMESPEC TsLeft;
- AssertReturn(RTTimeImplode(&TsLeft, &pLeft->Time), -1);
-
- RTTIMESPEC TsRight;
- AssertReturn(RTTimeImplode(&TsRight, &pRight->Time), 1);
-
- iDiff = RTTimeSpecCompare(&TsLeft, &TsRight);
- }
+ iDiff = RTTimeCompare(&pLeft->Time, &pRight->Time);
else
iDiff = -1;
}
diff --git a/src/VBox/Runtime/common/fs/isomakercmd.cpp b/src/VBox/Runtime/common/fs/isomakercmd.cpp
index 0588ebb..3498765 100644
--- a/src/VBox/Runtime/common/fs/isomakercmd.cpp
+++ b/src/VBox/Runtime/common/fs/isomakercmd.cpp
@@ -1959,12 +1959,15 @@ static int rtFsIsoMakerCmdAddSomething(PRTFSISOMAKERCMDOPTS pOpts, const char *p
if ( Parsed.aNames[i].cchPath > 0
&& (Parsed.aNames[i].fNameSpecifiers & RTFSISOMAKERCMDNAME_MAJOR_MASK))
{
+ /* Make sure we remove all objects by this name. */
pszFirstNm = Parsed.aNames[i].szPath;
- uint32_t idxObj = RTFsIsoMakerGetObjIdxForPath(pOpts->hIsoMaker,
- Parsed.aNames[i].fNameSpecifiers & RTFSISOMAKERCMDNAME_MAJOR_MASK,
- Parsed.aNames[i].szPath);
- if (idxObj != UINT32_MAX)
+ for (;;)
{
+ uint32_t idxObj = RTFsIsoMakerGetObjIdxForPath(pOpts->hIsoMaker,
+ Parsed.aNames[i].fNameSpecifiers & RTFSISOMAKERCMDNAME_MAJOR_MASK,
+ Parsed.aNames[i].szPath);
+ if (idxObj == UINT32_MAX)
+ break;
rc = RTFsIsoMakerObjRemove(pOpts->hIsoMaker, idxObj);
if (RT_FAILURE(rc))
return rtFsIsoMakerCmdErrorRc(pOpts, rc, "Failed to remove '%s': %Rrc", pszSpec, rc);
diff --git a/src/VBox/Runtime/common/fs/isomakerimport.cpp b/src/VBox/Runtime/common/fs/isomakerimport.cpp
index 09de1ab..2b7f1ea 100644
--- a/src/VBox/Runtime/common/fs/isomakerimport.cpp
+++ b/src/VBox/Runtime/common/fs/isomakerimport.cpp
@@ -591,9 +591,9 @@ static int rtFsIsoImportProcessIso9660AddAndNameFile(PRTFSISOMKIMPORTER pThis, P
}
else
{
+ pBlock2File->Core.pLeft = NULL;
+ pBlock2File->Core.pRight = NULL;
pBlock2FilePrev->pNext = pBlock2File;
- pBlock2FilePrev->Core.pLeft = NULL;
- pBlock2FilePrev->Core.pRight = NULL;
}
}
}
@@ -2440,6 +2440,14 @@ static int rtFsIsoImportProcessElToritoDesc(PRTFSISOMKIMPORTER pThis, PISO9660BO
{
uint8_t const *pbEntry = &pThis->abBuf[iEntry * ISO9660_ELTORITO_ENTRY_SIZE];
uint8_t const idHeader = *pbEntry;
+
+ /* KLUDGE ALERT! Older ISO images, like RHEL5-Server-20070208.0-x86_64-DVD.iso lacks
+ terminator entry. So, quietly stop with an entry that's all zeros. */
+ if ( idHeader == ISO9660_ELTORITO_BOOT_INDICATOR_NOT_BOOTABLE /* 0x00 */
+ && iEntry != 1 /* default */
+ && ASMMemIsZero(pbEntry, ISO9660_ELTORITO_ENTRY_SIZE))
+ return rc;
+
if ( iEntry == 1 /* default*/
|| idHeader == ISO9660_ELTORITO_BOOT_INDICATOR_BOOTABLE
|| idHeader == ISO9660_ELTORITO_BOOT_INDICATOR_NOT_BOOTABLE)
diff --git a/src/VBox/Runtime/common/misc/getopt.cpp b/src/VBox/Runtime/common/misc/getopt.cpp
index 034c6de..4b6f836 100644
--- a/src/VBox/Runtime/common/misc/getopt.cpp
+++ b/src/VBox/Runtime/common/misc/getopt.cpp
@@ -675,7 +675,7 @@ RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion)
}
else if (rc == VINF_SUCCESS)
{
- if (iThis + 1 >= pState->argc)
+ if (iThis + 1 + pState->cNonOptions >= pState->argc)
return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
pState->uIndex = uIndex;
pszValue = pState->argv[iThis + pState->cNonOptions + 1];
@@ -689,7 +689,7 @@ RTDECL(int) RTGetOpt(PRTGETOPTSTATE pState, PRTGETOPTUNION pValueUnion)
{
if (pszArgThis[cchLong] == '\0')
{
- if (iThis + 1 >= pState->argc)
+ if (iThis + 1 + pState->cNonOptions >= pState->argc)
return VERR_GETOPT_REQUIRED_ARGUMENT_MISSING;
pszValue = pState->argv[iThis + pState->cNonOptions + 1];
rtGetOptMoveArgvEntries(&pState->argv[iThis + 1], &pState->argv[iThis + pState->cNonOptions + 1]);
diff --git a/src/VBox/Runtime/common/time/time.cpp b/src/VBox/Runtime/common/time/time.cpp
index 33e864a..2e79ed9 100644
--- a/src/VBox/Runtime/common/time/time.cpp
+++ b/src/VBox/Runtime/common/time/time.cpp
@@ -56,6 +56,24 @@
/** The min nano second into the min day. (1677-09-21T00-12-43.145224192) */
#define RTTIME_MIN_DAY_NANO ( INT64_C(1000000000) * (00*3600 + 12*60 + 43) + 145224192 )
+/**
+ * Asserts that a_pTime is normalized.
+ */
+#define RTTIME_ASSERT_NORMALIZED(a_pTime) \
+ do \
+ { \
+ Assert(RT_ABS((a_pTime)->offUTC) <= 840); \
+ Assert((a_pTime)->u32Nanosecond < 1000000000); \
+ Assert((a_pTime)->u8Second < 60); \
+ Assert((a_pTime)->u8Minute < 60); \
+ Assert((a_pTime)->u8Hour < 24); \
+ Assert((a_pTime)->u8Month >= 1 && (a_pTime)->u8Month <= 12); \
+ Assert((a_pTime)->u8WeekDay < 7); \
+ Assert((a_pTime)->u16YearDay >= 1); \
+ Assert((a_pTime)->u16YearDay <= (rtTimeIsLeapYear((a_pTime)->i32Year) ? 366 : 365)); \
+ Assert((a_pTime)->u8MonthDay >= 1 && (a_pTime)->u8MonthDay <= 31); \
+ } while (0)
+
/*********************************************************************************************************************************
* Global Variables *
@@ -905,3 +923,187 @@ RTDECL(PRTTIMESPEC) RTTimeSpecFromString(PRTTIMESPEC pTime, const char *pszStrin
}
RT_EXPORT_SYMBOL(RTTimeSpecFromString);
+
+/**
+ * Adds one day to @a pTime.
+ *
+ * ASSUMES it is zulu time so DST can be ignored.
+ */
+static PRTTIME rtTimeAdd1Day(PRTTIME pTime)
+{
+ Assert(!pTime->offUTC);
+ rtTimeNormalizeInternal(pTime);
+ pTime->u8MonthDay += 1;
+ pTime->u16YearDay = 0;
+ return rtTimeNormalizeInternal(pTime);
+}
+
+
+/**
+ * Subtracts one day from @a pTime.
+ *
+ * ASSUMES it is zulu time so DST can be ignored.
+ */
+static PRTTIME rtTimeSub1Day(PRTTIME pTime)
+{
+ Assert(!pTime->offUTC);
+ rtTimeNormalizeInternal(pTime);
+ if (pTime->u16YearDay > 1)
+ {
+ pTime->u16YearDay -= 0;
+ pTime->u8Month = 0;
+ pTime->u8MonthDay = 0;
+ }
+ else
+ {
+ pTime->i32Year -= 1;
+ pTime->u16YearDay = rtTimeIsLeapYear(pTime->i32Year) ? 366 : 365;
+ pTime->u8MonthDay = 31;
+ pTime->u8Month = 12;
+ }
+ return rtTimeNormalizeInternal(pTime);
+}
+
+
+/**
+ * Adds a signed number of minutes to @a pTime.
+ *
+ * ASSUMES it is zulu time so DST can be ignored.
+ *
+ * @param pTime The time structure to work on.
+ * @param cAddend Number of minutes to add.
+ * ASSUMES the value isn't all that high!
+ */
+static PRTTIME rtTimeAddMinutes(PRTTIME pTime, int32_t cAddend)
+{
+ Assert(RT_ABS(cAddend) < 31 * 24 * 60);
+
+ /*
+ * Work on minutes of the day.
+ */
+ int32_t const cMinutesInDay = 24 * 60;
+ int32_t iDayMinute = (unsigned)pTime->u8Hour * 60 + pTime->u8Minute;
+ iDayMinute += cAddend;
+
+ while (iDayMinute >= cMinutesInDay)
+ {
+ rtTimeAdd1Day(pTime);
+ iDayMinute -= cMinutesInDay;
+ }
+
+ while (iDayMinute < 0)
+ {
+ rtTimeSub1Day(pTime);
+ iDayMinute += cMinutesInDay;
+ }
+
+ pTime->u8Hour = iDayMinute / 60;
+ pTime->u8Minute = iDayMinute % 60;
+
+ return pTime;
+}
+
+
+/**
+ * Converts @a pTime to zulu time (UTC) if needed.
+ *
+ * @returns pTime.
+ * @param pTime What to convers (in/out).
+ */
+static PRTTIME rtTimeConvertToZulu(PRTTIME pTime)
+{
+ RTTIME_ASSERT_NORMALIZED(pTime);
+ if ((pTime->fFlags & RTTIME_FLAGS_TYPE_MASK) != RTTIME_FLAGS_TYPE_UTC)
+ {
+ int32_t offUTC = pTime->offUTC;
+ pTime->offUTC = 0;
+ pTime->fFlags &= ~RTTIME_FLAGS_TYPE_MASK;
+ pTime->fFlags |= RTTIME_FLAGS_TYPE_UTC;
+ if (offUTC != 0)
+ rtTimeAddMinutes(pTime, offUTC);
+ }
+ return pTime;
+}
+
+
+/**
+ * Compares two normalized time structures.
+ *
+ * @retval 0 if equal.
+ * @retval -1 if @a pLeft is earlier than @a pRight.
+ * @retval 1 if @a pRight is earlier than @a pLeft.
+ *
+ * @param pLeft The left side time. NULL is accepted.
+ * @param pRight The right side time. NULL is accepted.
+ *
+ * @note A NULL time is considered smaller than anything else. If both are
+ * NULL, they are considered equal.
+ */
+RTDECL(int) RTTimeCompare(PCRTTIME pLeft, PCRTTIME pRight)
+{
+#ifdef RT_STRICT
+ if (pLeft)
+ RTTIME_ASSERT_NORMALIZED(pLeft);
+ if (pRight)
+ RTTIME_ASSERT_NORMALIZED(pRight);
+#endif
+
+ int iRet;
+ if (pLeft)
+ {
+ if (pRight)
+ {
+ /*
+ * Only work with normalized zulu time.
+ */
+ RTTIME TmpLeft;
+ if ( pLeft->offUTC != 0
+ || pLeft->u16YearDay == 0
+ || pLeft->u16YearDay > 366
+ || pLeft->u8Hour >= 60
+ || pLeft->u8Minute >= 60
+ || pLeft->u8Second >= 60)
+ {
+ TmpLeft = *pLeft;
+ pLeft = rtTimeConvertToZulu(rtTimeNormalizeInternal(&TmpLeft));
+ }
+
+ RTTIME TmpRight;
+ if ( pRight->offUTC != 0
+ || pRight->u16YearDay == 0
+ || pRight->u16YearDay > 366
+ || pRight->u8Hour >= 60
+ || pRight->u8Minute >= 60
+ || pRight->u8Second >= 60)
+ {
+ TmpRight = *pRight;
+ pRight = rtTimeConvertToZulu(rtTimeNormalizeInternal(&TmpRight));
+ }
+
+ /*
+ * Do the comparison.
+ */
+ if ( pLeft->i32Year != pRight->i32Year)
+ iRet = pLeft->i32Year < pRight->i32Year ? -1 : 1;
+ else if ( pLeft->u16YearDay != pRight->u16YearDay)
+ iRet = pLeft->u16YearDay < pRight->u16YearDay ? -1 : 1;
+ else if ( pLeft->u8Hour != pRight->u8Hour)
+ iRet = pLeft->u8Hour < pRight->u8Hour ? -1 : 1;
+ else if ( pLeft->u8Minute != pRight->u8Minute)
+ iRet = pLeft->u8Minute < pRight->u8Minute ? -1 : 1;
+ else if ( pLeft->u8Second != pRight->u8Second)
+ iRet = pLeft->u8Second < pRight->u8Second ? -1 : 1;
+ else if ( pLeft->u32Nanosecond != pRight->u32Nanosecond)
+ iRet = pLeft->u32Nanosecond < pRight->u32Nanosecond ? -1 : 1;
+ else
+ iRet = 0;
+ }
+ else
+ iRet = 1;
+ }
+ else
+ iRet = pRight ? -1 : 0;
+ return iRet;
+}
+RT_EXPORT_SYMBOL(RTTimeCompare);
+
diff --git a/src/VBox/Runtime/r3/fileio.cpp b/src/VBox/Runtime/r3/fileio.cpp
index a74490b..e9ba425 100644
--- a/src/VBox/Runtime/r3/fileio.cpp
+++ b/src/VBox/Runtime/r3/fileio.cpp
@@ -500,13 +500,13 @@ RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS
/* advance */
off += cbBlock;
- if (pfnProgress && offNextPercent < off)
+ if (pfnProgress && offNextPercent < off && uPercentage < 100)
{
- while (offNextPercent < off)
+ do
{
uPercentage++;
offNextPercent += cbPercent;
- }
+ } while (offNextPercent < off && uPercentage < 100);
rc = pfnProgress(uPercentage, pvUser);
if (RT_FAILURE(rc))
break;
diff --git a/src/VBox/Runtime/testcase/tstRTGetOpt.cpp b/src/VBox/Runtime/testcase/tstRTGetOpt.cpp
index 94afcbd..1969a21 100644
--- a/src/VBox/Runtime/testcase/tstRTGetOpt.cpp
+++ b/src/VBox/Runtime/testcase/tstRTGetOpt.cpp
@@ -637,6 +637,20 @@ int main()
CHECK(Val.pDef == NULL);
CHECK(argc4 == GetState.iNext);
+ /*
+ * Some negative testing.
+ */
+ const char *argv5[] =
+ {
+ "non-option-argument",
+ "--optwithstring", /* missing string */
+ /* done */
+ NULL
+ };
+ int argc5 = (int)RT_ELEMENTS(argv5) - 1;
+ CHECK(RT_SUCCESS(RTGetOptInit(&GetState, argc5, (char **)argv5, &s_aOpts2[0], RT_ELEMENTS(s_aOpts2), 0,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST)));
+ RTTESTI_CHECK_RC(RTGetOpt(&GetState, &Val), VERR_GETOPT_REQUIRED_ARGUMENT_MISSING);
/*
diff --git a/src/VBox/Storage/QCOW.cpp b/src/VBox/Storage/QCOW.cpp
index cfe601f..b673ab7 100644
--- a/src/VBox/Storage/QCOW.cpp
+++ b/src/VBox/Storage/QCOW.cpp
@@ -1288,7 +1288,7 @@ static int qcowCreateImage(PQCOWIMAGE pImage, uint64_t cbSize,
pImage->cL1TableEntries = cbSize / (pImage->cbCluster * pImage->cL2TableEntries);
if (cbSize % (pImage->cbCluster * pImage->cL2TableEntries))
pImage->cL1TableEntries++;
- pImage->cbL1Table = pImage->cL1TableEntries * sizeof(uint64_t);
+ pImage->cbL1Table = RT_ALIGN_64(pImage->cL1TableEntries * sizeof(uint64_t), pImage->cbCluster);
pImage->offL1Table = QCOW_V1_HDR_SIZE;
pImage->cbBackingFilename = 0;
pImage->offBackingFilename = 0;
@@ -1589,7 +1589,7 @@ static DECLCALLBACK(int) qcowCreate(const char *pszFilename, uint64_t cbSize,
void **ppBackendData)
{
RT_NOREF1(pUuid);
- LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p",
+ LogFlowFunc(("pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p Uuid=%RTuuid uOpenFlags=%#x uPercentStart=%u uPercentSpan=%u pVDIfsDisk=%#p pVDIfsImage=%#p pVDIfsOperation=%#p enmType=%u ppBackendData=%#p\n",
pszFilename, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, pUuid, uOpenFlags, uPercentStart, uPercentSpan, pVDIfsDisk, pVDIfsImage, pVDIfsOperation, enmType, ppBackendData));
int rc;
diff --git a/src/VBox/Storage/VMDK.cpp b/src/VBox/Storage/VMDK.cpp
index 24c6385..3b1897e 100644
--- a/src/VBox/Storage/VMDK.cpp
+++ b/src/VBox/Storage/VMDK.cpp
@@ -1930,7 +1930,9 @@ static int vmdkPreprocessDescriptor(PVMDKIMAGE pImage, char *pDescData,
if (RT_SUCCESS(rc))
{
if ( strcmp(pDescriptor->aLines[0], "# Disk DescriptorFile")
- && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File"))
+ && strcmp(pDescriptor->aLines[0], "# Disk Descriptor File")
+ && strcmp(pDescriptor->aLines[0], "#Disk Descriptor File")
+ && strcmp(pDescriptor->aLines[0], "#Disk DescriptorFile"))
rc = vdIfError(pImage->pIfError, VERR_VD_VMDK_INVALID_HEADER, RT_SRC_POS,
N_("VMDK: descriptor does not start as expected in '%s'"), pImage->pszFilename);
else
diff --git a/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp b/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp
index e5f8fb4..c625e3f 100644
--- a/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp
+++ b/src/VBox/VMM/VMMAll/CPUMAllMsrs.cpp
@@ -1422,6 +1422,51 @@ static DECLCALLBACK(VBOXSTRICTRC) cpumMsrRd_Ia32VmxVmFunc(PVMCPU pVCpu, uint32_t
}
+/** @callback_method_impl{FNCPUMRDMSR} */
+static DECLCALLBACK(VBOXSTRICTRC) cpumMsrRd_Ia32SpecCtrl(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
+{
+ RT_NOREF_PV(pVCpu); RT_NOREF_PV(idMsr); RT_NOREF_PV(pRange);
+ *puValue = pVCpu->cpum.s.GuestMsrs.msr.SpecCtrl;
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNCPUMWRMSR} */
+static DECLCALLBACK(VBOXSTRICTRC) cpumMsrWr_Ia32SpecCtrl(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
+{
+ RT_NOREF_PV(pVCpu); RT_NOREF_PV(idMsr); RT_NOREF_PV(pRange); RT_NOREF_PV(uValue); RT_NOREF_PV(uRawValue);
+
+ /* NB: The STIBP bit can be set even when IBRS is present, regardless of whether STIBP is actually implemented. */
+ if (uValue & ~(MSR_IA32_SPEC_CTRL_F_IBRS | MSR_IA32_SPEC_CTRL_F_STIBP))
+ {
+ Log(("CPUM: Invalid IA32_SPEC_CTRL bits (trying to write %#llx)\n", uValue));
+ return VERR_CPUM_RAISE_GP_0;
+ }
+
+ pVCpu->cpum.s.GuestMsrs.msr.SpecCtrl = uValue;
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNCPUMWRMSR} */
+static DECLCALLBACK(VBOXSTRICTRC) cpumMsrWr_Ia32PredCmd(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue)
+{
+ RT_NOREF_PV(pVCpu); RT_NOREF_PV(idMsr); RT_NOREF_PV(pRange); RT_NOREF_PV(uValue); RT_NOREF_PV(uRawValue);
+ return VINF_SUCCESS;
+}
+
+
+/** @callback_method_impl{FNCPUMRDMSR} */
+static DECLCALLBACK(VBOXSTRICTRC) cpumMsrRd_Ia32ArchCapabilities(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
+{
+ RT_NOREF_PV(pVCpu); RT_NOREF_PV(idMsr); RT_NOREF_PV(pRange);
+ *puValue = pVCpu->cpum.s.GuestMsrs.msr.ArchCaps;
+ return VINF_SUCCESS;
+}
+
+
+
+
@@ -4977,6 +5022,8 @@ static const PFNCPUMRDMSR g_aCpumRdMsrFns[kCpumMsrRdFn_End] =
cpumMsrRd_Ia32VmxTrueExitCtls,
cpumMsrRd_Ia32VmxTrueEntryCtls,
cpumMsrRd_Ia32VmxVmFunc,
+ cpumMsrRd_Ia32SpecCtrl,
+ cpumMsrRd_Ia32ArchCapabilities,
cpumMsrRd_Amd64Efer,
cpumMsrRd_Amd64SyscallTarget,
@@ -5220,6 +5267,8 @@ static const PFNCPUMWRMSR g_aCpumWrMsrFns[kCpumMsrWrFn_End] =
cpumMsrWr_Ia32TscDeadline,
cpumMsrWr_Ia32X2ApicN,
cpumMsrWr_Ia32DebugInterface,
+ cpumMsrWr_Ia32SpecCtrl,
+ cpumMsrWr_Ia32PredCmd,
cpumMsrWr_Amd64Efer,
cpumMsrWr_Amd64SyscallTarget,
@@ -5690,6 +5739,8 @@ int cpumR3MsrStrictInitChecks(void)
CPUM_ASSERT_RD_MSR_FN(Ia32VmxTrueExitCtls);
CPUM_ASSERT_RD_MSR_FN(Ia32VmxTrueEntryCtls);
CPUM_ASSERT_RD_MSR_FN(Ia32VmxVmFunc);
+ CPUM_ASSERT_RD_MSR_FN(Ia32SpecCtrl);
+ CPUM_ASSERT_RD_MSR_FN(Ia32ArchCapabilities);
CPUM_ASSERT_RD_MSR_FN(Amd64Efer);
CPUM_ASSERT_RD_MSR_FN(Amd64SyscallTarget);
@@ -5922,6 +5973,8 @@ int cpumR3MsrStrictInitChecks(void)
CPUM_ASSERT_WR_MSR_FN(Ia32TscDeadline);
CPUM_ASSERT_WR_MSR_FN(Ia32X2ApicN);
CPUM_ASSERT_WR_MSR_FN(Ia32DebugInterface);
+ CPUM_ASSERT_WR_MSR_FN(Ia32SpecCtrl);
+ CPUM_ASSERT_WR_MSR_FN(Ia32PredCmd);
CPUM_ASSERT_WR_MSR_FN(Amd64Efer);
CPUM_ASSERT_WR_MSR_FN(Amd64SyscallTarget);
@@ -6220,5 +6273,30 @@ VMMR0_INT_DECL(void) CPUMR0SetGuestTscAux(PVMCPU pVCpu, uint64_t uValue)
pVCpu->cpum.s.GuestMsrs.msr.TscAux = uValue;
}
+/**
+ * Fast way for HM to access the IA32_SPEC_CTRL register.
+ *
+ * @returns The register value.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @thread EMT(pVCpu)
+ */
+VMMR0_INT_DECL(uint64_t) CPUMR0GetGuestSpecCtrl(PVMCPU pVCpu)
+{
+ return pVCpu->cpum.s.GuestMsrs.msr.SpecCtrl;
+}
+
+
+/**
+ * Fast way for HM to access the IA32_SPEC_CTRL register.
+ *
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param uValue The new value.
+ * @thread EMT(pVCpu)
+ */
+VMMR0_INT_DECL(void) CPUMR0SetGuestSpecCtrl(PVMCPU pVCpu, uint64_t uValue)
+{
+ pVCpu->cpum.s.GuestMsrs.msr.SpecCtrl = uValue;
+}
+
#endif /* IN_RING0 */
diff --git a/src/VBox/VMM/VMMAll/IEMAll.cpp b/src/VBox/VMM/VMMAll/IEMAll.cpp
index c8f371f..615c680 100644
--- a/src/VBox/VMM/VMMAll/IEMAll.cpp
+++ b/src/VBox/VMM/VMMAll/IEMAll.cpp
@@ -886,6 +886,7 @@ IEM_STATIC VBOXSTRICTRC iemMemStackPushU32(PVMCPU pVCpu, uint32_t u32Value);
IEM_STATIC VBOXSTRICTRC iemMemStackPushU16(PVMCPU pVCpu, uint16_t u16Value);
IEM_STATIC VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPU pVCpu, uint16_t uSel);
IEM_STATIC uint16_t iemSRegFetchU16(PVMCPU pVCpu, uint8_t iSegReg);
+IEM_STATIC uint64_t iemSRegBaseFetchU64(PVMCPU pVCpu, uint8_t iSegReg);
#if defined(IEM_VERIFICATION_MODE_FULL) && !defined(IEM_VERIFICATION_MODE_MINIMAL)
IEM_STATIC PIEMVERIFYEVTREC iemVerifyAllocRecord(PVMCPU pVCpu);
@@ -6141,6 +6142,20 @@ DECLINLINE(uint16_t) iemSRegFetchU16(PVMCPU pVCpu, uint8_t iSegReg)
/**
+ * Fetches the base address value of a segment register.
+ *
+ * @returns The selector value.
+ * @param pVCpu The cross context virtual CPU structure of the calling thread.
+ * @param iSegReg The segment register.
+ */
+DECLINLINE(uint64_t) iemSRegBaseFetchU64(PVMCPU pVCpu, uint8_t iSegReg)
+{
+ Assert(iSegReg < X86_SREG_COUNT);
+ return IEM_GET_CTX(pVCpu)->aSRegs[iSegReg].u64Base;
+}
+
+
+/**
* Gets a reference (pointer) to the specified general purpose register.
*
* @returns Register reference.
@@ -6224,6 +6239,21 @@ DECLINLINE(uint64_t *) iemGRegRefU64(PVMCPU pVCpu, uint8_t iReg)
/**
+ * Gets a reference (pointer) to the specified segment register's base address.
+ *
+ * @returns Segment register base address reference.
+ * @param pVCpu The cross context virtual CPU structure of the calling thread.
+ * @param iSegReg The segment selector.
+ */
+DECLINLINE(uint64_t *) iemSRegBaseRefU64(PVMCPU pVCpu, uint8_t iSegReg)
+{
+ Assert(iSegReg < X86_SREG_COUNT);
+ PCPUMCTX pCtx = IEM_GET_CTX(pVCpu);
+ return &pCtx->aSRegs[iSegReg].u64Base;
+}
+
+
+/**
* Fetches the value of a 8-bit general purpose register.
*
* @returns The register value.
@@ -11211,6 +11241,18 @@ IEM_STATIC VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPU pVCpu, uint16_t uSel)
if (!((a_EffAddr) & ((a_cbAlign) - 1))) { /* likely */ } \
else return iemRaiseGeneralProtectionFault0(pVCpu); \
} while (0)
+#define IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT() \
+ do { \
+ if ( pVCpu->iem.s.enmCpuMode != IEMMODE_64BIT \
+ || !IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fFsGsBase \
+ || !(IEM_GET_CTX(pVCpu)->cr4 & X86_CR4_FSGSBASE)) \
+ return iemRaiseUndefinedOpcode(pVCpu); \
+ } while (0)
+#define IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0(a_u64Addr) \
+ do { \
+ if (!IEM_IS_CANONICAL(a_u64Addr)) \
+ return iemRaiseGeneralProtectionFault0(pVCpu); \
+ } while (0)
#define IEM_MC_LOCAL(a_Type, a_Name) a_Type a_Name
@@ -11248,6 +11290,8 @@ IEM_STATIC VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPU pVCpu, uint16_t uSel)
#define IEM_MC_FETCH_SREG_U16(a_u16Dst, a_iSReg) (a_u16Dst) = iemSRegFetchU16(pVCpu, (a_iSReg))
#define IEM_MC_FETCH_SREG_ZX_U32(a_u32Dst, a_iSReg) (a_u32Dst) = iemSRegFetchU16(pVCpu, (a_iSReg))
#define IEM_MC_FETCH_SREG_ZX_U64(a_u64Dst, a_iSReg) (a_u64Dst) = iemSRegFetchU16(pVCpu, (a_iSReg))
+#define IEM_MC_FETCH_SREG_BASE_U64(a_u64Dst, a_iSReg) (a_u64Dst) = iemSRegBaseFetchU64(pVCpu, (a_iSReg));
+#define IEM_MC_FETCH_SREG_BASE_U32(a_u32Dst, a_iSReg) (a_u32Dst) = iemSRegBaseFetchU64(pVCpu, (a_iSReg));
#define IEM_MC_FETCH_CR0_U16(a_u16Dst) (a_u16Dst) = (uint16_t)(pVCpu)->iem.s.CTX_SUFF(pCtx)->cr0
#define IEM_MC_FETCH_CR0_U32(a_u32Dst) (a_u32Dst) = (uint32_t)(pVCpu)->iem.s.CTX_SUFF(pCtx)->cr0
#define IEM_MC_FETCH_CR0_U64(a_u64Dst) (a_u64Dst) = (pVCpu)->iem.s.CTX_SUFF(pCtx)->cr0
@@ -11273,9 +11317,12 @@ IEM_STATIC VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPU pVCpu, uint16_t uSel)
#define IEM_MC_STORE_GREG_U64_CONST IEM_MC_STORE_GREG_U64
#define IEM_MC_CLEAR_HIGH_GREG_U64(a_iGReg) *iemGRegRefU64(pVCpu, (a_iGReg)) &= UINT32_MAX
#define IEM_MC_CLEAR_HIGH_GREG_U64_BY_REF(a_pu32Dst) do { (a_pu32Dst)[1] = 0; } while (0)
+#define IEM_MC_STORE_SREG_BASE_U64(a_iSeg, a_u64Value) *iemSRegBaseRefU64(pVCpu, (a_iSeg)) = (a_u64Value)
+#define IEM_MC_STORE_SREG_BASE_U32(a_iSeg, a_u32Value) *iemSRegBaseRefU64(pVCpu, (a_iSeg)) = (uint32_t)(a_u32Value) /* clear high bits. */
#define IEM_MC_STORE_FPUREG_R80_SRC_REF(a_iSt, a_pr80Src) \
do { IEM_GET_CTX(pVCpu)->CTX_SUFF(pXState)->x87.aRegs[a_iSt].r80 = *(a_pr80Src); } while (0)
+
#define IEM_MC_REF_GREG_U8(a_pu8Dst, a_iGReg) (a_pu8Dst) = iemGRegRefU8( pVCpu, (a_iGReg))
#define IEM_MC_REF_GREG_U16(a_pu16Dst, a_iGReg) (a_pu16Dst) = iemGRegRefU16(pVCpu, (a_iGReg))
/** @todo User of IEM_MC_REF_GREG_U32 needs to clear the high bits on commit.
@@ -16012,6 +16059,26 @@ VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpg(PVMCPU pVCpu, uint8_t cbInstr, R
/**
+ * Interface for HM and EM to emulate the INVPCID instruction.
+ *
+ * @param pVCpu The cross context virtual CPU structure.
+ * @param cbInstr The instruction length in bytes.
+ * @param uType The invalidation type.
+ * @param GCPtrInvpcidDesc The effective address of the INVPCID descriptor.
+ *
+ * @remarks In ring-0 not all of the state needs to be synced in.
+ */
+VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvpcid(PVMCPU pVCpu, uint8_t cbInstr, uint8_t uType, RTGCPTR GCPtrInvpcidDesc)
+{
+ IEMEXEC_ASSERT_INSTR_LEN_RETURN(cbInstr, 4);
+
+ iemInitExec(pVCpu, false /*fBypassHandlers*/);
+ VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_invpcid, uType, GCPtrInvpcidDesc);
+ return iemUninitExecAndFiddleStatusAndMaybeReenter(pVCpu, rcStrict);
+}
+
+
+/**
* Checks if IEM is in the process of delivering an event (interrupt or
* exception).
*
diff --git a/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h b/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
index 9182f16..c030adb 100644
--- a/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
+++ b/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
@@ -5185,6 +5185,13 @@ IEM_CIMPL_DEF_4(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX, IEMACCESS
return iemRaiseGeneralProtectionFault0(pVCpu);
}
+ if ( !(uNewCrX & X86_CR0_PG)
+ && (pCtx->cr4 & X86_CR4_PCIDE))
+ {
+ Log(("Trying to clear CR0.PG while leaving CR4.PCID set\n"));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+
/* Long mode consistency checks. */
if ( (uNewCrX & X86_CR0_PG)
&& !(uOldCrX & X86_CR0_PG)
@@ -5305,6 +5312,17 @@ IEM_CIMPL_DEF_4(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX, IEMACCESS
* enabling paging. */
case 3:
{
+ /* clear bit 63 from the source operand and indicate no invalidations are required. */
+ if ( (pCtx->cr4 & X86_CR4_PCIDE)
+ && (uNewCrX & RT_BIT_64(63)))
+ {
+ /** @todo r=ramshankar: avoiding a TLB flush altogether here causes Windows 10
+ * SMP(w/o nested-paging) to hang during bootup on Skylake systems, see
+ * Intel spec. 4.10.4.1 "Operations that Invalidate TLBs and
+ * Paging-Structure Caches". */
+ uNewCrX &= ~RT_BIT_64(63);
+ }
+
/* check / mask the value. */
if (uNewCrX & UINT64_C(0xfff0000000000000))
{
@@ -5379,16 +5397,32 @@ IEM_CIMPL_DEF_4(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX, IEMACCESS
// fValid |= X86_CR4_VMXE;
if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fXSaveRstor)
fValid |= X86_CR4_OSXSAVE;
+ if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fPcid)
+ fValid |= X86_CR4_PCIDE;
+ if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fFsGsBase)
+ fValid |= X86_CR4_FSGSBASE;
if (uNewCrX & ~(uint64_t)fValid)
{
Log(("Trying to set reserved CR4 bits: NewCR4=%#llx InvalidBits=%#llx\n", uNewCrX, uNewCrX & ~(uint64_t)fValid));
return iemRaiseGeneralProtectionFault0(pVCpu);
}
- /* long mode checks. */
- if ( (uOldCrX & X86_CR4_PAE)
- && !(uNewCrX & X86_CR4_PAE)
- && CPUMIsGuestInLongModeEx(pCtx) )
+ bool const fPcide = ((uNewCrX ^ uOldCrX) & X86_CR4_PCIDE) && (uNewCrX & X86_CR4_PCIDE);
+ bool const fLongMode = CPUMIsGuestInLongModeEx(pCtx);
+
+ /* PCIDE check. */
+ if ( fPcide
+ && ( !fLongMode
+ || (pCtx->cr3 & UINT64_C(0xfff))))
+ {
+ Log(("Trying to set PCIDE with invalid PCID or outside long mode. Pcid=%#x\n", (pCtx->cr3 & UINT64_C(0xfff))));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+
+ /* PAE check. */
+ if ( fLongMode
+ && (uOldCrX & X86_CR4_PAE)
+ && !(uNewCrX & X86_CR4_PAE))
{
Log(("Trying to set clear CR4.PAE while long mode is active\n"));
return iemRaiseGeneralProtectionFault0(pVCpu);
@@ -5429,7 +5463,7 @@ IEM_CIMPL_DEF_4(iemCImpl_load_CrX, uint8_t, iCrReg, uint64_t, uNewCrX, IEMACCESS
}
/* PGM - flushing and mode. */
- if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE))
+ if ((uNewCrX ^ uOldCrX) & (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_PCIDE /* | X86_CR4_SMEP */))
{
rc = PGMFlushTLB(pVCpu, pCtx->cr3, true /* global */);
AssertRCReturn(rc, rc);
@@ -5777,6 +5811,109 @@ IEM_CIMPL_DEF_1(iemCImpl_invlpg, RTGCPTR, GCPtrPage)
/**
+ * Implements INVPCID.
+ *
+ * @param uInvpcidType The invalidation type.
+ * @param GCPtrInvpcidDesc The effective address of invpcid descriptor.
+ * @remarks Updates the RIP.
+ */
+IEM_CIMPL_DEF_2(iemCImpl_invpcid, uint64_t, uInvpcidType, RTGCPTR, GCPtrInvpcidDesc)
+{
+ /*
+ * Check preconditions.
+ */
+ if (!IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fInvpcid)
+ return iemRaiseUndefinedOpcode(pVCpu);
+ if (pVCpu->iem.s.uCpl != 0)
+ {
+ Log(("invpcid: CPL != 0 -> #GP(0)\n"));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+ if (IEM_IS_V86_MODE(pVCpu))
+ {
+ Log(("invpcid: v8086 mode -> #GP(0)\n"));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+ if (uInvpcidType > X86_INVPCID_TYPE_MAX_VALID)
+ {
+ Log(("invpcid: invalid/unrecognized invpcid type %#x -> #GP(0)\n", uInvpcidType));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+
+ /*
+ * Fetch the invpcid descriptor from guest memory.
+ */
+ RTUINT128U uDesc;
+ VBOXSTRICTRC rcStrict = iemMemFetchDataU128(pVCpu, &uDesc, pVCpu->iem.s.iEffSeg, GCPtrInvpcidDesc);
+ if (rcStrict == VINF_SUCCESS)
+ {
+ /*
+ * Validate the descriptor.
+ */
+ if (uDesc.s.Lo > 0xfff)
+ {
+ Log(("invpcid: reserved bits set in invpcid descriptor %#RX64 -> #GP(0)\n", uDesc.s.Lo));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+
+ RTGCUINTPTR64 const GCPtrInvAddr = uDesc.s.Hi;
+ uint8_t const uPcid = uDesc.s.Lo & UINT64_C(0xfff);
+ uint32_t const uCr4 = IEM_GET_CTX(pVCpu)->cr4;
+ uint64_t const uCr3 = IEM_GET_CTX(pVCpu)->cr3;
+ switch (uInvpcidType)
+ {
+ case X86_INVPCID_TYPE_INDV_ADDR:
+ {
+ if (!IEM_IS_CANONICAL(GCPtrInvAddr))
+ {
+ Log(("invpcid: invalidation address %#RGP is not canonical -> #GP(0)\n", GCPtrInvAddr));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+ if ( !(uCr4 & X86_CR4_PCIDE)
+ && uPcid != 0)
+ {
+ Log(("invpcid: invalid pcid %#x\n", uPcid));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+
+ /* Invalidate mappings for the linear address tagged with PCID except global translations. */
+ PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
+ break;
+ }
+
+ case X86_INVPCID_TYPE_SINGLE_CONTEXT:
+ {
+ if ( !(uCr4 & X86_CR4_PCIDE)
+ && uPcid != 0)
+ {
+ Log(("invpcid: invalid pcid %#x\n", uPcid));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
+ /* Invalidate all mappings associated with PCID except global translations. */
+ PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
+ break;
+ }
+
+ case X86_INVPCID_TYPE_ALL_CONTEXT_INCL_GLOBAL:
+ {
+ PGMFlushTLB(pVCpu, uCr3, true /* fGlobal */);
+ break;
+ }
+
+ case X86_INVPCID_TYPE_ALL_CONTEXT_EXCL_GLOBAL:
+ {
+ PGMFlushTLB(pVCpu, uCr3, false /* fGlobal */);
+ break;
+ }
+ IEM_NOT_REACHED_DEFAULT_CASE_RET();
+ }
+ iemRegAddToRipAndClearRF(pVCpu, cbInstr);
+ }
+ return rcStrict;
+}
+
+
+/**
* Implements RDTSC.
*/
IEM_CIMPL_DEF_0(iemCImpl_rdtsc)
diff --git a/src/VBox/VMM/VMMAll/IEMAllInstructionsThree0f38.cpp.h b/src/VBox/VMM/VMMAll/IEMAllInstructionsThree0f38.cpp.h
index e6aaa28..101ed80 100644
--- a/src/VBox/VMM/VMMAll/IEMAllInstructionsThree0f38.cpp.h
+++ b/src/VBox/VMM/VMMAll/IEMAllInstructionsThree0f38.cpp.h
@@ -306,7 +306,40 @@ FNIEMOP_STUB(iemOp_invept_Gy_Mdq);
/** Opcode 0x66 0x0f 0x38 0x81. */
FNIEMOP_STUB(iemOp_invvpid_Gy_Mdq);
/** Opcode 0x66 0x0f 0x38 0x82. */
-FNIEMOP_STUB(iemOp_invpcid_Gy_Mdq);
+FNIEMOP_DEF(iemOp_invpcid_Gy_Mdq)
+{
+ IEMOP_MNEMONIC(invpcid, "invpcid Gy,Mdq");
+ IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
+ uint8_t bRm; IEM_OPCODE_GET_NEXT_U8(&bRm);
+ if ((bRm & X86_MODRM_MOD_MASK) != (3 << X86_MODRM_MOD_SHIFT))
+ {
+ /* Register, memory. */
+ if (pVCpu->iem.s.enmEffOpSize == IEMMODE_64BIT)
+ {
+ IEM_MC_BEGIN(2, 0);
+ IEM_MC_ARG(uint64_t, uInvpcidType, 0);
+ IEM_MC_ARG(RTGCPTR, GCPtrInvpcidDesc, 1);
+ IEM_MC_FETCH_GREG_U64(uInvpcidType, ((bRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) | pVCpu->iem.s.uRexReg);
+ IEM_MC_CALC_RM_EFF_ADDR(GCPtrInvpcidDesc, bRm, 0);
+ IEM_MC_CALL_CIMPL_2(iemCImpl_invpcid, uInvpcidType, GCPtrInvpcidDesc);
+ IEM_MC_END();
+ }
+ else
+ {
+ IEM_MC_BEGIN(2, 0);
+ IEM_MC_ARG(uint32_t, uInvpcidType, 0);
+ IEM_MC_ARG(RTGCPTR, GCPtrInvpcidDesc, 1);
+ IEM_MC_FETCH_GREG_U32(uInvpcidType, ((bRm >> X86_MODRM_REG_SHIFT) & X86_MODRM_REG_SMASK) | pVCpu->iem.s.uRexReg);
+ IEM_MC_CALC_RM_EFF_ADDR(GCPtrInvpcidDesc, bRm, 0);
+ IEM_MC_CALL_CIMPL_2(iemCImpl_invpcid, uInvpcidType, GCPtrInvpcidDesc);
+ IEM_MC_END();
+ }
+ }
+ Log(("iemOp_invpcid_Gy_Mdq: invalid encoding -> #UD\n"));
+ return IEMOP_RAISE_INVALID_OPCODE();
+}
+
+
/* Opcode 0x66 0x0f 0x38 0x83 - invalid. */
/* Opcode 0x66 0x0f 0x38 0x84 - invalid. */
/* Opcode 0x66 0x0f 0x38 0x85 - invalid. */
diff --git a/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h b/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h
index c416089..650ca89 100644
--- a/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h
+++ b/src/VBox/VMM/VMMAll/IEMAllInstructionsTwoByte0f.cpp.h
@@ -6988,16 +6988,118 @@ FNIEMOP_DEF_1(iemOp_Grp15_sfence, uint8_t, bRm)
/** Opcode 0xf3 0x0f 0xae 11b/0. */
-FNIEMOP_UD_STUB_1(iemOp_Grp15_rdfsbase, uint8_t, bRm);
+FNIEMOP_DEF_1(iemOp_Grp15_rdfsbase, uint8_t, bRm)
+{
+ IEMOP_MNEMONIC(rdfsbase, "rdfsbase Ry");
+ IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
+ if (pVCpu->iem.s.enmEffOpSize == IEMMODE_64BIT)
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint64_t, u64Dst, 0);
+ IEM_MC_FETCH_SREG_BASE_U64(u64Dst, X86_SREG_FS);
+ IEM_MC_STORE_GREG_U64((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB, u64Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ else
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint32_t, u32Dst, 0);
+ IEM_MC_FETCH_SREG_BASE_U32(u32Dst, X86_SREG_FS);
+ IEM_MC_STORE_GREG_U32((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB, u32Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ return VINF_SUCCESS;
+}
/** Opcode 0xf3 0x0f 0xae 11b/1. */
-FNIEMOP_UD_STUB_1(iemOp_Grp15_rdgsbase, uint8_t, bRm);
+FNIEMOP_DEF_1(iemOp_Grp15_rdgsbase, uint8_t, bRm)
+{
+ IEMOP_MNEMONIC(rdgsbase, "rdgsbase Ry");
+ IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
+ if (pVCpu->iem.s.enmEffOpSize == IEMMODE_64BIT)
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint64_t, u64Dst, 0);
+ IEM_MC_FETCH_SREG_BASE_U64(u64Dst, X86_SREG_GS);
+ IEM_MC_STORE_GREG_U64((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB, u64Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ else
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint32_t, u32Dst, 0);
+ IEM_MC_FETCH_SREG_BASE_U32(u32Dst, X86_SREG_GS);
+ IEM_MC_STORE_GREG_U32((bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB, u32Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ return VINF_SUCCESS;
+}
/** Opcode 0xf3 0x0f 0xae 11b/2. */
-FNIEMOP_UD_STUB_1(iemOp_Grp15_wrfsbase, uint8_t, bRm);
+FNIEMOP_DEF_1(iemOp_Grp15_wrfsbase, uint8_t, bRm)
+{
+ IEMOP_MNEMONIC(wrfsbase, "wrfsbase Ry");
+ IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
+ if (pVCpu->iem.s.enmEffOpSize == IEMMODE_64BIT)
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint64_t, u64Dst, 0);
+ IEM_MC_FETCH_GREG_U64(u64Dst, (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB);
+ IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0(u64Dst);
+ IEM_MC_STORE_SREG_BASE_U64(X86_SREG_FS, u64Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ else
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint32_t, u32Dst, 0);
+ IEM_MC_FETCH_GREG_U32(u32Dst, (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB);
+ IEM_MC_STORE_SREG_BASE_U64(X86_SREG_FS, u32Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ return VINF_SUCCESS;
+}
/** Opcode 0xf3 0x0f 0xae 11b/3. */
-FNIEMOP_UD_STUB_1(iemOp_Grp15_wrgsbase, uint8_t, bRm);
+FNIEMOP_DEF_1(iemOp_Grp15_wrgsbase, uint8_t, bRm)
+{
+ IEMOP_MNEMONIC(wrgsbase, "wrgsbase Ry");
+ IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
+ if (pVCpu->iem.s.enmEffOpSize == IEMMODE_64BIT)
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint64_t, u64Dst, 0);
+ IEM_MC_FETCH_GREG_U64(u64Dst, (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB);
+ IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0(u64Dst);
+ IEM_MC_STORE_SREG_BASE_U64(X86_SREG_GS, u64Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ else
+ {
+ IEM_MC_BEGIN(1, 0);
+ IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT();
+ IEM_MC_ARG(uint32_t, u32Dst, 0);
+ IEM_MC_FETCH_GREG_U32(u32Dst, (bRm & X86_MODRM_RM_MASK) | pVCpu->iem.s.uRexB);
+ IEM_MC_STORE_SREG_BASE_U64(X86_SREG_GS, u32Dst);
+ IEM_MC_ADVANCE_RIP();
+ IEM_MC_END();
+ }
+ return VINF_SUCCESS;
+}
/**
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index 20810ac..0c9c3a2 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -2467,6 +2467,13 @@ static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
hmR0VmxSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
}
#endif
+ /*
+ * The IA32_PRED_CMD MSR is write-only and has no state associated with it. We never need to intercept
+ * access (writes need to be executed without exiting, reds will #GP-fault anyway).
+ */
+ if (pVM->cpum.ro.GuestFeatures.fIbpb)
+ hmR0VmxSetMsrPermission(pVCpu, MSR_IA32_PRED_CMD, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
+
/* Though MSR_IA32_PERF_GLOBAL_CTRL is saved/restored lazily, we want intercept reads/write to it for now. */
}
@@ -2500,16 +2507,14 @@ static int hmR0VmxSetupProcCtls(PVM pVM, PVMCPU pVCpu)
if (pVM->hm.s.fNestedPaging)
val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT; /* Enable EPT. */
- else
- {
- /*
- * Without Nested Paging, INVPCID should cause a VM-exit. Enabling this bit causes the CPU to refer to
- * VMX_VMCS_CTRL_PROC_EXEC_INVLPG_EXIT when INVPCID is executed by the guest.
- * See Intel spec. 25.4 "Changes to instruction behaviour in VMX non-root operation".
- */
- if (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
- val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
- }
+
+ /*
+ * Enable the INVPCID instruction if supported by the hardware and we expose
+ * it to the guest. Without this, guest executing INVPCID would cause a #UD.
+ */
+ if ( (pVM->hm.s.vmx.Msrs.VmxProcCtls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_INVPCID)
+ && pVM->cpum.ro.GuestFeatures.fInvpcid)
+ val |= VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
if (pVM->hm.s.vmx.fVpid)
val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID; /* Enable VPID. */
@@ -4118,6 +4123,8 @@ static VBOXSTRICTRC hmR0VmxLoadGuestCR3AndCR4(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
| X86_CR4_VMXE;
if (pVM->cpum.ro.HostFeatures.fXSaveRstor)
u32CR4Mask |= X86_CR4_OSXSAVE;
+ if (pVM->cpum.ro.GuestFeatures.fPcid)
+ u32CR4Mask |= X86_CR4_PCIDE;
pVCpu->hm.s.vmx.u32CR4Mask = u32CR4Mask;
rc = VMXWriteVmcs32(VMX_VMCS_CTRL_CR4_MASK, u32CR4Mask);
AssertRCReturn(rc, rc);
@@ -6603,6 +6610,7 @@ static int hmR0VmxSaveGuestAutoLoadStoreMsrs(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
case MSR_K6_STAR: pMixedCtx->msrSTAR = pMsr->u64Value; break;
case MSR_K8_SF_MASK: pMixedCtx->msrSFMASK = pMsr->u64Value; break;
case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value; break;
+ case MSR_IA32_SPEC_CTRL: CPUMR0SetGuestSpecCtrl(pVCpu, pMsr->u64Value); break;
case MSR_K6_EFER: /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
break;
@@ -9147,6 +9155,21 @@ static void hmR0VmxPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCt
}
}
+ if (pVM->cpum.ro.GuestFeatures.fIbrs)
+ {
+ bool fMsrUpdated;
+ int rc2 = hmR0VmxSaveGuestAutoLoadStoreMsrs(pVCpu, pMixedCtx);
+ AssertRC(rc2);
+ Assert(HMVMXCPU_GST_IS_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_AUTO_LOAD_STORE_MSRS));
+
+ rc2 = hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_IA32_SPEC_CTRL, CPUMR0GetGuestSpecCtrl(pVCpu), true /* fUpdateHostMsr */,
+ &fMsrUpdated);
+ AssertRC(rc2);
+ Assert(fMsrUpdated || pVCpu->hm.s.vmx.fUpdatedHostMsrs);
+ /* Finally, mark that all host MSR values are updated so we don't redo it without leaving VT-x. See @bugref{6956}. */
+ pVCpu->hm.s.vmx.fUpdatedHostMsrs = true;
+ }
+
#ifdef VBOX_STRICT
hmR0VmxCheckAutoLoadStoreMsrs(pVCpu);
hmR0VmxCheckHostEferMsr(pVCpu);
diff --git a/src/VBox/VMM/VMMR0/VMMR0.cpp b/src/VBox/VMM/VMMR0/VMMR0.cpp
index 011df27..2fe15e3 100644
--- a/src/VBox/VMM/VMMR0/VMMR0.cpp
+++ b/src/VBox/VMM/VMMR0/VMMR0.cpp
@@ -152,6 +152,8 @@ PFNRT g_VMMR0Deps[] =
extern "C" { char _depends_on[] = "vboxdrv"; }
#endif
+/** The result of SUPR0GetRawModeUsability(), set by ModuleInit(). */
+int g_rcRawModeUsability = VINF_SUCCESS;
/**
@@ -239,7 +241,11 @@ DECLEXPORT(int) ModuleInit(void *hMod)
VMM_CHECK_SMAP_CHECK(rc = VERR_VMM_SMAP_BUT_AC_CLEAR);
if (RT_SUCCESS(rc))
{
- LogFlow(("ModuleInit: returns success.\n"));
+ g_rcRawModeUsability = SUPR0GetRawModeUsability();
+ if (g_rcRawModeUsability != VINF_SUCCESS)
+ SUPR0Printf("VMMR0!ModuleInit: SUPR0GetRawModeUsability -> %Rrc\n",
+ g_rcRawModeUsability);
+ LogFlow(("ModuleInit: returns success\n"));
return VINF_SUCCESS;
}
}
@@ -1006,6 +1012,13 @@ VMMR0DECL(void) VMMR0EntryFast(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION
break;
}
# endif
+ if (RT_SUCCESS(g_rcRawModeUsability))
+ { /* likely */ }
+ else
+ {
+ pVCpu->vmm.s.iLastGZRc = g_rcRawModeUsability;
+ break;
+ }
/*
* Disable preemption.
@@ -1567,6 +1580,8 @@ static int vmmR0EntryExWorker(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION
if (RT_UNLIKELY(!PGMGetHyperCR3(pVCpu)))
return VERR_PGM_NO_CR3_SHADOW_ROOT;
# endif
+ if (RT_FAILURE(g_rcRawModeUsability))
+ return g_rcRawModeUsability;
/*
* Disable interrupts.
diff --git a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
index 59134ab..551fcc2 100644
--- a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
+++ b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
@@ -1734,19 +1734,24 @@ int cpumR3CpuIdExplodeFeatures(PCCPUMCPUIDLEAF paLeaves, uint32_t cLeaves, PCPUM
pFeatures->fMonitorMWait = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_MONITOR);
pFeatures->fMovCmpXchg16b = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_CX16);
pFeatures->fClFlush = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_CLFSH);
+ pFeatures->fPcid = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_PCID);
/* Structured extended features. */
PCCPUMCPUIDLEAF const pSxfLeaf0 = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 7, 0);
if (pSxfLeaf0)
{
+ pFeatures->fFsGsBase = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
pFeatures->fAvx2 = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX2);
pFeatures->fAvx512Foundation = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX512F);
pFeatures->fClFlushOpt = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT);
+ pFeatures->fInvpcid = RT_BOOL(pSxfLeaf0->uEbx & X86_CPUID_STEXT_FEATURE_EBX_INVPCID);
pFeatures->fIbpb = RT_BOOL(pSxfLeaf0->uEdx & X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB);
pFeatures->fIbrs = pFeatures->fIbpb;
pFeatures->fStibp = RT_BOOL(pSxfLeaf0->uEdx & X86_CPUID_STEXT_FEATURE_EDX_STIBP);
+#if 0 // Disabled until IA32_ARCH_CAPABILITIES support can be tested
pFeatures->fArchCap = RT_BOOL(pSxfLeaf0->uEdx & X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP);
+#endif
}
/* MWAIT/MONITOR leaf. */
@@ -2336,6 +2341,9 @@ typedef struct CPUMCPUIDCONFIG
CPUMISAEXTCFG enmRdRand;
CPUMISAEXTCFG enmRdSeed;
CPUMISAEXTCFG enmCLFlushOpt;
+ CPUMISAEXTCFG enmFsGsBase;
+ CPUMISAEXTCFG enmPcid;
+ CPUMISAEXTCFG enmInvpcid;
CPUMISAEXTCFG enmAbm;
CPUMISAEXTCFG enmSse4A;
@@ -2670,7 +2678,7 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
/* ECX Bit 14 - xTPR Update Control. Processor supports changing IA32_MISC_ENABLES[bit 23]. */
//| X86_CPUID_FEATURE_ECX_TPRUPDATE
//| X86_CPUID_FEATURE_ECX_PDCM - not implemented yet.
- //| X86_CPUID_FEATURE_ECX_PCID - not implemented yet.
+ | (pConfig->enmPcid ? X86_CPUID_FEATURE_ECX_PCID : 0)
//| X86_CPUID_FEATURE_ECX_DCA - not implemented yet.
| (pConfig->enmSse41 ? X86_CPUID_FEATURE_ECX_SSE4_1 : 0)
| (pConfig->enmSse42 ? X86_CPUID_FEATURE_ECX_SSE4_2 : 0)
@@ -2687,10 +2695,19 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
//| X86_CPUID_FEATURE_ECX_HVP - Set explicitly later.
;
+ /* Mask out PCID unless FSGSBASE is exposed due to a bug in Windows 10 SMP guests, see @bugref{9089#c15}. */
+ if ( !pVM->cpum.s.GuestFeatures.fFsGsBase
+ && (pStdFeatureLeaf->uEcx & X86_CPUID_FEATURE_ECX_PCID))
+ {
+ pStdFeatureLeaf->uEcx &= ~X86_CPUID_FEATURE_ECX_PCID;
+ LogRel(("CPUM: Disabled PCID without FSGSBASE to workaround buggy guests\n"));
+ }
+
if (pCpum->u8PortableCpuIdLevel > 0)
{
PORTABLE_CLEAR_BITS_WHEN(1, pStdFeatureLeaf->uEax, ProcessorType, (UINT32_C(3) << 12), (UINT32_C(2) << 12));
PORTABLE_DISABLE_FEATURE_BIT( 1, pStdFeatureLeaf->uEcx, SSSE3, X86_CPUID_FEATURE_ECX_SSSE3);
+ PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, PCID, X86_CPUID_FEATURE_ECX_PCID, pConfig->enmPcid);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, SSE4_1, X86_CPUID_FEATURE_ECX_SSE4_1, pConfig->enmSse41);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, SSE4_2, X86_CPUID_FEATURE_ECX_SSE4_2, pConfig->enmSse42);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pStdFeatureLeaf->uEcx, MOVBE, X86_CPUID_FEATURE_ECX_MOVBE, pConfig->enmMovBe);
@@ -3081,7 +3098,7 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
{
pCurLeaf->uEax = 0; /* Max ECX input is 0. */
pCurLeaf->uEbx &= 0
- //| X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE RT_BIT(0)
+ | (pConfig->enmFsGsBase ? X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE : 0)
//| X86_CPUID_STEXT_FEATURE_EBX_TSC_ADJUST RT_BIT(1)
//| X86_CPUID_STEXT_FEATURE_EBX_SGX RT_BIT(2)
//| X86_CPUID_STEXT_FEATURE_EBX_BMI1 RT_BIT(3)
@@ -3091,7 +3108,7 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
//| X86_CPUID_STEXT_FEATURE_EBX_SMEP RT_BIT(7)
//| X86_CPUID_STEXT_FEATURE_EBX_BMI2 RT_BIT(8)
//| X86_CPUID_STEXT_FEATURE_EBX_ERMS RT_BIT(9)
- //| X86_CPUID_STEXT_FEATURE_EBX_INVPCID RT_BIT(10)
+ | (pConfig->enmInvpcid ? X86_CPUID_STEXT_FEATURE_EBX_INVPCID : 0)
//| X86_CPUID_STEXT_FEATURE_EBX_RTM RT_BIT(11)
//| X86_CPUID_STEXT_FEATURE_EBX_PQM RT_BIT(12)
| X86_CPUID_STEXT_FEATURE_EBX_DEPR_FPU_CS_DS
@@ -3117,16 +3134,28 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
pCurLeaf->uEcx &= 0
//| X86_CPUID_STEXT_FEATURE_ECX_PREFETCHWT1 - we do not do vector functions yet.
;
- pCurLeaf->uEdx &= 0; /** @todo X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB, X86_CPUID_STEXT_FEATURE_EDX_STIBP and X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP */
+ pCurLeaf->uEdx &= 0
+ //| X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB RT_BIT(26)
+ //| X86_CPUID_STEXT_FEATURE_EDX_STIBP RT_BIT(27)
+ //| X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP RT_BIT(29)
+ ;
+
+ /* Mask out INVPCID unless FSGSBASE is exposed due to a bug in Windows 10 SMP guests, see @bugref{9089#c15}. */
+ if ( !pVM->cpum.s.GuestFeatures.fFsGsBase
+ && (pCurLeaf->uEbx & X86_CPUID_STEXT_FEATURE_EBX_INVPCID))
+ {
+ pCurLeaf->uEbx &= ~X86_CPUID_STEXT_FEATURE_EBX_INVPCID;
+ LogRel(("CPUM: Disabled INVPCID without FSGSBASE to work around buggy guests\n"));
+ }
if (pCpum->u8PortableCpuIdLevel > 0)
{
- PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, FSGSBASE, X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
+ PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pCurLeaf->uEbx, FSGSBASE, X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE, pConfig->enmFsGsBase);
PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, SGX, X86_CPUID_STEXT_FEATURE_EBX_SGX);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pCurLeaf->uEbx, AVX2, X86_CPUID_STEXT_FEATURE_EBX_AVX2, pConfig->enmAvx2);
PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, SMEP, X86_CPUID_STEXT_FEATURE_EBX_SMEP);
PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, BMI2, X86_CPUID_STEXT_FEATURE_EBX_BMI2);
- PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, INVPCID, X86_CPUID_STEXT_FEATURE_EBX_INVPCID);
+ PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pCurLeaf->uEbx, INVPCID, X86_CPUID_STEXT_FEATURE_EBX_INVPCID, pConfig->enmInvpcid);
PORTABLE_DISABLE_FEATURE_BIT( 1, pCurLeaf->uEbx, AVX512F, X86_CPUID_STEXT_FEATURE_EBX_AVX512F);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pCurLeaf->uEbx, RDSEED, X86_CPUID_STEXT_FEATURE_EBX_RDSEED, pConfig->enmRdSeed);
PORTABLE_DISABLE_FEATURE_BIT_CFG(1, pCurLeaf->uEbx, CLFLUSHOPT, X86_CPUID_STEXT_FEATURE_EBX_RDSEED, pConfig->enmCLFlushOpt);
@@ -3139,12 +3168,16 @@ static int cpumR3CpuIdSanitize(PVM pVM, PCPUM pCpum, PCPUMCPUIDCONFIG pConfig)
}
/* Force standard feature bits. */
+ if (pConfig->enmFsGsBase == CPUMISAEXTCFG_ENABLED_ALWAYS)
+ pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE;
if (pConfig->enmAvx2 == CPUMISAEXTCFG_ENABLED_ALWAYS)
pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_AVX2;
if (pConfig->enmRdSeed == CPUMISAEXTCFG_ENABLED_ALWAYS)
pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_RDSEED;
if (pConfig->enmCLFlushOpt == CPUMISAEXTCFG_ENABLED_ALWAYS)
pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT;
+ if (pConfig->enmInvpcid == CPUMISAEXTCFG_ENABLED_ALWAYS)
+ pCurLeaf->uEbx |= X86_CPUID_STEXT_FEATURE_EBX_INVPCID;
break;
}
@@ -3911,6 +3944,9 @@ static int cpumR3CpuIdReadConfig(PVM pVM, PCPUMCPUIDCONFIG pConfig, PCFGMNODE pC
"|RDRAND"
"|RDSEED"
"|CLFLUSHOPT"
+ "|FSGSBASE"
+ "|PCID"
+ "|INVPCID"
"|ABM"
"|SSE4A"
"|MISALNSSE"
@@ -4048,6 +4084,24 @@ static int cpumR3CpuIdReadConfig(PVM pVM, PCPUMCPUIDCONFIG pConfig, PCFGMNODE pC
rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "CLFLUSHOPT", &pConfig->enmCLFlushOpt, fNestedPagingAndFullGuestExec);
AssertLogRelRCReturn(rc, rc);
+ /** @cfgm{/CPUM/IsaExts/FSGSBASE, isaextcfg, true}
+ * Whether to expose the read/write FSGSBASE instructions to the guest.
+ */
+ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "FSGSBASE", &pConfig->enmFsGsBase, true);
+ AssertLogRelRCReturn(rc, rc);
+
+ /** @cfgm{/CPUM/IsaExts/PCID, isaextcfg, true}
+ * Whether to expose the PCID feature to the guest.
+ */
+ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "PCID", &pConfig->enmPcid, pConfig->enmFsGsBase);
+ AssertLogRelRCReturn(rc, rc);
+
+ /** @cfgm{/CPUM/IsaExts/INVPCID, isaextcfg, true}
+ * Whether to expose the INVPCID instruction to the guest.
+ */
+ rc = cpumR3CpuIdReadIsaExtCfg(pVM, pIsaExts, "INVPCID", &pConfig->enmInvpcid, pConfig->enmFsGsBase);
+ AssertLogRelRCReturn(rc, rc);
+
/* AMD: */
@@ -4249,6 +4303,12 @@ int cpumR3InitCpuIdAndMsrs(PVM pVM)
if (fEnable)
CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_NX);
+ /* Check if speculation control is enabled. */
+ rc = CFGMR3QueryBoolDef(pCpumCfg, "SpecCtrl", &fEnable, false);
+ AssertRCReturn(rc, rc);
+ if (fEnable)
+ CPUMR3SetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_SPEC_CTRL);
+
return VINF_SUCCESS;
}
@@ -4529,6 +4589,94 @@ VMMR3_INT_DECL(void) CPUMR3SetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFea
LogRel(("CPUM: SetGuestCpuIdFeature: Enabled MWAIT Extensions.\n"));
break;
+ /*
+ * Set up the speculation control CPUID bits and MSRs. This is quite complicated
+ * on Intel CPUs, and different on AMDs.
+ */
+ case CPUMCPUIDFEATURE_SPEC_CTRL:
+ if (pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_INTEL)
+ {
+ pLeaf = cpumR3CpuIdGetExactLeaf(&pVM->cpum.s, UINT32_C(0x00000007), 0);
+ if ( !pLeaf
+ || !(pVM->cpum.s.HostFeatures.fIbpb || pVM->cpum.s.HostFeatures.fIbrs))
+ {
+ LogRel(("CPUM: WARNING! Can't turn on Speculation Control when the host doesn't support it!\n"));
+ return;
+ }
+
+ /* The feature can be enabled. Let's see what we can actually do. */
+ pVM->cpum.s.GuestFeatures.fSpeculationControl = 1;
+
+ /* We will only expose STIBP if IBRS is present to keep things simpler (simple is not an option). */
+ if (pVM->cpum.s.HostFeatures.fIbrs)
+ {
+ pLeaf->uEdx |= X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB;
+ pVM->cpum.s.GuestFeatures.fIbrs = 1;
+ if (pVM->cpum.s.HostFeatures.fStibp)
+ {
+ pLeaf->uEdx |= X86_CPUID_STEXT_FEATURE_EDX_STIBP;
+ pVM->cpum.s.GuestFeatures.fStibp = 1;
+ }
+
+ /* Make sure we have the speculation control MSR... */
+ pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_SPEC_CTRL);
+ if (!pMsrRange)
+ {
+ static CPUMMSRRANGE const s_SpecCtrl =
+ {
+ /*.uFirst =*/ MSR_IA32_SPEC_CTRL, /*.uLast =*/ MSR_IA32_SPEC_CTRL,
+ /*.enmRdFn =*/ kCpumMsrRdFn_Ia32SpecCtrl, /*.enmWrFn =*/ kCpumMsrWrFn_Ia32SpecCtrl,
+ /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ 0,
+ /*.szName = */ "IA32_SPEC_CTRL"
+ };
+ int rc = CPUMR3MsrRangesInsert(pVM, &s_SpecCtrl);
+ AssertLogRelRC(rc);
+ }
+
+ /* ... and the predictor command MSR. */
+ pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_PRED_CMD);
+ if (!pMsrRange)
+ {
+ static CPUMMSRRANGE const s_SpecCtrl =
+ {
+ /*.uFirst =*/ MSR_IA32_PRED_CMD, /*.uLast =*/ MSR_IA32_PRED_CMD,
+ /*.enmRdFn =*/ kCpumMsrRdFn_WriteOnly, /*.enmWrFn =*/ kCpumMsrWrFn_Ia32PredCmd,
+ /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ 0,
+ /*.szName = */ "IA32_PRED_CMD"
+ };
+ int rc = CPUMR3MsrRangesInsert(pVM, &s_SpecCtrl);
+ AssertLogRelRC(rc);
+ }
+
+ }
+
+ if (pVM->cpum.s.HostFeatures.fArchCap) {
+ pLeaf->uEdx |= X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP;
+
+ /* Install the architectural capabilities MSR. */
+ pMsrRange = cpumLookupMsrRange(pVM, MSR_IA32_ARCH_CAPABILITIES);
+ if (!pMsrRange)
+ {
+ static CPUMMSRRANGE const s_ArchCaps =
+ {
+ /*.uFirst =*/ MSR_IA32_ARCH_CAPABILITIES, /*.uLast =*/ MSR_IA32_ARCH_CAPABILITIES,
+ /*.enmRdFn =*/ kCpumMsrRdFn_Ia32ArchCapabilities, /*.enmWrFn =*/ kCpumMsrWrFn_ReadOnly,
+ /*.offCpumCpu =*/ UINT16_MAX, /*.fReserved =*/ 0, /*.uValue =*/ 0, /*.fWrIgnMask =*/ 0, /*.fWrGpMask =*/ UINT64_MAX,
+ /*.szName = */ "IA32_ARCH_CAPABILITIES"
+ };
+ int rc = CPUMR3MsrRangesInsert(pVM, &s_ArchCaps);
+ AssertLogRelRC(rc);
+ }
+ }
+
+ LogRel(("CPUM: SetGuestCpuIdFeature: Enabled Speculation Control.\n"));
+ }
+ else if (pVM->cpum.s.GuestFeatures.enmCpuVendor == CPUMCPUVENDOR_AMD)
+ {
+ /* The precise details of AMD's implementation are not yet clear. */
+ }
+ break;
+
default:
AssertMsgFailed(("enmFeature=%d\n", enmFeature));
break;
@@ -4567,6 +4715,7 @@ VMMR3_INT_DECL(bool) CPUMR3GetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFea
case CPUMCPUIDFEATURE_RDTSCP: return pVM->cpum.s.GuestFeatures.fRdTscP;
case CPUMCPUIDFEATURE_HVP: return pVM->cpum.s.GuestFeatures.fHypervisorPresent;
case CPUMCPUIDFEATURE_MWAIT_EXTS: return pVM->cpum.s.GuestFeatures.fMWaitExtensions;
+ case CPUMCPUIDFEATURE_SPEC_CTRL: return pVM->cpum.s.GuestFeatures.fSpeculationControl;
case CPUMCPUIDFEATURE_INVALID:
case CPUMCPUIDFEATURE_32BIT_HACK:
@@ -4679,6 +4828,14 @@ VMMR3_INT_DECL(void) CPUMR3ClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmF
Log(("CPUM: ClearGuestCpuIdFeature: Disabled MWAIT Extensions!\n"));
break;
+ case CPUMCPUIDFEATURE_SPEC_CTRL:
+ pLeaf = cpumR3CpuIdGetExactLeaf(&pVM->cpum.s, UINT32_C(0x00000007), 0);
+ if (pLeaf)
+ /*pVM->cpum.s.aGuestCpuIdPatmStd[7].uEdx =*/ pLeaf->uEdx &= ~(X86_CPUID_STEXT_FEATURE_EDX_IBRS_IBPB | X86_CPUID_STEXT_FEATURE_EDX_STIBP | X86_CPUID_STEXT_FEATURE_EDX_ARCHCAP);
+ pVM->cpum.s.GuestFeatures.fSpeculationControl = 0;
+ Log(("CPUM: ClearGuestCpuIdFeature: Disabled speculation control!\n"));
+ break;
+
default:
AssertMsgFailed(("enmFeature=%d\n", enmFeature));
break;
@@ -5183,7 +5340,7 @@ int cpumR3LoadCpuIdInner(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, PCPUMCPUID
CPUID_RAW_FEATURE_IGN(Std, uEcx, X86_CPUID_FEATURE_ECX_TPRUPDATE);
CPUID_RAW_FEATURE_IGN(Std, uEcx, X86_CPUID_FEATURE_ECX_PDCM);
CPUID_RAW_FEATURE_RET(Std, uEcx, RT_BIT_32(16) /*reserved*/);
- CPUID_RAW_FEATURE_IGN(Std, uEcx, X86_CPUID_FEATURE_ECX_PCID);
+ CPUID_RAW_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_PCID);
CPUID_RAW_FEATURE_IGN(Std, uEcx, X86_CPUID_FEATURE_ECX_DCA);
CPUID_RAW_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_SSE4_1);
CPUID_RAW_FEATURE_RET(Std, uEcx, X86_CPUID_FEATURE_ECX_SSE4_2);
@@ -6788,6 +6945,7 @@ DECLCALLBACK(void) cpumR3CpuIdInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszA
pCurLeaf = cpumR3CpuIdGetLeaf(paLeaves, cLeaves, UINT32_C(0x80000008), 0);
if (pCurLeaf != NULL)
{
+ ASMCpuIdExSlow(UINT32_C(0x80000008), 0, 0, 0, &Host.uEax, &Host.uEbx, &Host.uEcx, &Host.uEdx);
if (pCurLeaf->uEbx || (Host.uEbx && iVerbosity))
{
if (iVerbosity < 1)
diff --git a/src/VBox/VMM/VMMR3/HM.cpp b/src/VBox/VMM/VMMR3/HM.cpp
index a940578..4457ba7 100644
--- a/src/VBox/VMM/VMMR3/HM.cpp
+++ b/src/VBox/VMM/VMMR3/HM.cpp
@@ -133,6 +133,7 @@ static const char * const g_apszVTxExitReasons[MAX_EXITREASON_STAT] =
EXIT_REASON(VMX_EXIT_INVVPID , 53, "INVVPID instruction."),
EXIT_REASON(VMX_EXIT_WBINVD , 54, "WBINVD instruction."),
EXIT_REASON(VMX_EXIT_XSETBV , 55, "XSETBV instruction."),
+ EXIT_REASON(VMX_EXIT_APIC_WRITE , 56, "APIC write completed to virtual-APIC page."),
EXIT_REASON(VMX_EXIT_RDRAND , 57, "RDRAND instruction."),
EXIT_REASON(VMX_EXIT_INVPCID , 58, "INVPCID instruction."),
EXIT_REASON(VMX_EXIT_VMFUNC , 59, "VMFUNC instruction."),
@@ -453,6 +454,7 @@ VMMR3_INT_DECL(int) HMR3Init(PVM pVM)
"|EnableVPID"
"|IBPBOnVMExit"
"|IBPBOnVMEntry"
+ "|SpecCtrlByHost"
"|TPRPatchingEnabled"
"|64bitEnabled"
"|VmxPleGap"
@@ -609,6 +611,11 @@ VMMR3_INT_DECL(int) HMR3Init(PVM pVM)
rc = CFGMR3QueryBoolDef(pCfgHm, "IBPBOnVMEntry", &pVM->hm.s.fIbpbOnVmEntry, false);
AssertLogRelRCReturn(rc, rc);
+ /** @cfgm{/HM/SpecCtrlByHost, bool}
+ * Another expensive paranoia setting. */
+ rc = CFGMR3QueryBoolDef(pCfgHm, "SpecCtrlByHost", &pVM->hm.s.fSpecCtrlByHost, false);
+ AssertLogRelRCReturn(rc, rc);
+
/*
* Check if VT-x or AMD-v support according to the users wishes.
*/
diff --git a/src/VBox/VMM/VMMR3/PDMDevice.cpp b/src/VBox/VMM/VMMR3/PDMDevice.cpp
index 6dee7c9..e1b46f6 100644
--- a/src/VBox/VMM/VMMR3/PDMDevice.cpp
+++ b/src/VBox/VMM/VMMR3/PDMDevice.cpp
@@ -243,14 +243,18 @@ int pdmR3DevInit(PVM pVM)
Assert(i == cDevs);
/*
- * Sort the device array ascending on u32Order. (bubble)
+ * Sort (bubble) the device array ascending on u32Order and instance number
+ * for a device.
*/
unsigned c = cDevs - 1;
while (c)
{
unsigned j = 0;
for (i = 0; i < c; i++)
- if (paDevs[i].u32Order > paDevs[i + 1].u32Order)
+ if ( paDevs[i].u32Order > paDevs[i + 1].u32Order
+ || ( paDevs[i].u32Order == paDevs[i + 1].u32Order
+ && paDevs[i].iInstance > paDevs[i + 1].iInstance
+ && paDevs[i].pDev == paDevs[i + 1].pDev) )
{
paDevs[cDevs] = paDevs[i + 1];
paDevs[i + 1] = paDevs[i];
diff --git a/src/VBox/VMM/VMMR3/VMM.cpp b/src/VBox/VMM/VMMR3/VMM.cpp
index a10bc27..9635482 100644
--- a/src/VBox/VMM/VMMR3/VMM.cpp
+++ b/src/VBox/VMM/VMMR3/VMM.cpp
@@ -662,13 +662,17 @@ VMMR3_INT_DECL(int) VMMR3InitRC(PVM pVM)
break;
}
- if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
+ /* Don't trigger assertions or guru if raw-mode is unavailable. */
+ if (rc != VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT)
{
- VMMR3FatalDump(pVM, pVCpu, rc);
- if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
- rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
+ if (RT_FAILURE(rc) || (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST))
+ {
+ VMMR3FatalDump(pVM, pVCpu, rc);
+ if (rc >= VINF_EM_FIRST && rc <= VINF_EM_LAST)
+ rc = VERR_IPE_UNEXPECTED_INFO_STATUS;
+ }
+ AssertRC(rc);
}
- AssertRC(rc);
}
return rc;
}
diff --git a/src/VBox/VMM/include/HMInternal.h b/src/VBox/VMM/include/HMInternal.h
index c5672e3..f49779e 100644
--- a/src/VBox/VMM/include/HMInternal.h
+++ b/src/VBox/VMM/include/HMInternal.h
@@ -420,8 +420,10 @@ typedef struct HM
bool fIbpbOnVmExit;
/** Set if indirect branch prediction barrier on VM entry. */
bool fIbpbOnVmEntry;
+ /** Set if host manages speculation control settings. */
+ bool fSpecCtrlByHost;
/** Explicit padding. */
- bool afPadding[3];
+ bool afPadding[2];
/** Maximum ASID allowed. */
uint32_t uMaxAsid;
diff --git a/src/VBox/VMM/testcase/tstIEMCheckMc.cpp b/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
index 722b528..63e1b77 100644
--- a/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
+++ b/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
@@ -361,6 +361,8 @@ IEMOPMEDIAF2 g_iemAImpl_pcmpeqd;
#define IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO() do {} while (0)
#define IEM_MC_RAISE_GP0_IF_EFF_ADDR_UNALIGNED(a_EffAddr, a_cbAlign) \
do { AssertCompile(RT_IS_POWER_OF_TWO(a_cbAlign)); CHK_TYPE(RTGCPTR, a_EffAddr); } while (0)
+#define IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT() do {} while (0)
+#define IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0(a_u64Addr) do {} while (0)
#define IEM_MC_LOCAL(a_Type, a_Name) \
a_Type a_Name; NOREF(a_Name)
@@ -423,6 +425,8 @@ IEMOPMEDIAF2 g_iemAImpl_pcmpeqd;
#define IEM_MC_FETCH_SREG_U16(a_u16Dst, a_iSReg) do { (a_u16Dst) = 0; CHK_TYPE(uint16_t, a_u16Dst); } while (0)
#define IEM_MC_FETCH_SREG_ZX_U32(a_u32Dst, a_iSReg) do { (a_u32Dst) = 0; CHK_TYPE(uint32_t, a_u32Dst); } while (0)
#define IEM_MC_FETCH_SREG_ZX_U64(a_u64Dst, a_iSReg) do { (a_u64Dst) = 0; CHK_TYPE(uint64_t, a_u64Dst); } while (0)
+#define IEM_MC_FETCH_SREG_BASE_U64(a_u64Dst, a_iSReg) do { (a_u64Dst) = 0; CHK_TYPE(uint64_t, a_u64Dst); } while (0)
+#define IEM_MC_FETCH_SREG_BASE_U32(a_u32Dst, a_iSReg) do { (a_u32Dst) = 0; CHK_TYPE(uint32_t, a_u32Dst); } while (0)
#define IEM_MC_FETCH_CR0_U16(a_u16Dst) do { (a_u16Dst) = 0; CHK_TYPE(uint16_t, a_u16Dst); } while (0)
#define IEM_MC_FETCH_CR0_U32(a_u32Dst) do { (a_u32Dst) = 0; CHK_TYPE(uint32_t, a_u32Dst); } while (0)
#define IEM_MC_FETCH_CR0_U64(a_u64Dst) do { (a_u64Dst) = 0; CHK_TYPE(uint64_t, a_u64Dst); } while (0)
@@ -447,6 +451,8 @@ IEMOPMEDIAF2 g_iemAImpl_pcmpeqd;
#define IEM_MC_STORE_FPUREG_R80_SRC_REF(a_iSt, a_pr80Src) do { CHK_PTYPE(PCRTFLOAT80U, a_pr80Src); Assert((a_iSt) < 8); } while (0)
#define IEM_MC_CLEAR_HIGH_GREG_U64(a_iGReg) do { } while (0)
#define IEM_MC_CLEAR_HIGH_GREG_U64_BY_REF(a_pu32Dst) do { CHK_PTYPE(uint32_t *, a_pu32Dst); } while (0)
+#define IEM_MC_STORE_SREG_BASE_U64(a_iSeg, a_u64Value) do { } while (0)
+#define IEM_MC_STORE_SREG_BASE_U32(a_iSeg, a_u32Value) do { } while (0)
#define IEM_MC_REF_GREG_U8(a_pu8Dst, a_iGReg) do { (a_pu8Dst) = (uint8_t *)((uintptr_t)0); CHK_PTYPE(uint8_t *, a_pu8Dst); } while (0)
#define IEM_MC_REF_GREG_U16(a_pu16Dst, a_iGReg) do { (a_pu16Dst) = (uint16_t *)((uintptr_t)0); CHK_PTYPE(uint16_t *, a_pu16Dst); } while (0)
#define IEM_MC_REF_GREG_U32(a_pu32Dst, a_iGReg) do { (a_pu32Dst) = (uint32_t *)((uintptr_t)0); CHK_PTYPE(uint32_t *, a_pu32Dst); } while (0)
--
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